diff options
Diffstat (limited to 'src')
256 files changed, 12784 insertions, 4437 deletions
diff --git a/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java b/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java index bbfe72b08..30b3fd278 100644 --- a/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java +++ b/src/jogl/classes/com/jogamp/audio/windows/waveout/Mixer.java @@ -36,6 +36,9 @@ import java.io.*; import java.nio.*; import java.util.*; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; + // Needed only for NIO workarounds on CVM import java.lang.reflect.*; @@ -43,9 +46,10 @@ public class Mixer { // This class is a singleton private static Mixer mixer; - private volatile boolean shutdown; - private volatile Object shutdownLock = new Object(); - private volatile boolean shutdownDone; + volatile boolean fillerAlive; + volatile boolean mixerAlive; + volatile boolean shutdown; + volatile Object shutdownLock = new Object(); // Windows Event object private final long event; @@ -63,6 +67,9 @@ public class Mixer { private Mixer() { event = CreateEvent(); + fillerAlive = false; + mixerAlive = false; + shutdown = false; new FillerThread().start(); final MixerThread m = new MixerThread(); m.setPriority(Thread.MAX_PRIORITY - 1); @@ -118,50 +125,57 @@ public class Mixer { shutdown = true; SetEvent(event); try { - shutdownLock.wait(); + while(fillerAlive || mixerAlive) { + shutdownLock.wait(); + } } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } } } - class FillerThread extends Thread { + class FillerThread extends InterruptSource.Thread { FillerThread() { - super("Mixer Thread"); + super(null, null, "Mixer Thread"); } @Override public void run() { - while (!shutdown) { - final List<Track> curTracks = tracks; + fillerAlive = true; + try { + while (!shutdown) { + final List<Track> curTracks = tracks; - for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) { - final Track track = iter.next(); + for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) { + final Track track = iter.next(); + try { + track.fill(); + } catch (final IOException e) { + e.printStackTrace(); + remove(track); + } + } try { - track.fill(); - } catch (final IOException e) { - e.printStackTrace(); - remove(track); + // Run ten times per second + java.lang.Thread.sleep(100); + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } } - - try { - // Run ten times per second - Thread.sleep(100); - } catch (final InterruptedException e) { - e.printStackTrace(); - } + } finally { + fillerAlive = false; } } } - class MixerThread extends Thread { + class MixerThread extends InterruptSource.Thread { // Temporary mixing buffer // Interleaved left and right channels float[] mixingBuffer; private final Vec3f temp = new Vec3f(); MixerThread() { - super("Mixer Thread"); + super(null, null, "Mixer Thread"); if (!initializeWaveOut(event)) { throw new InternalError("Error initializing waveout device"); } @@ -169,108 +183,113 @@ public class Mixer { @Override public void run() { - while (!shutdown) { - // Get the next buffer - final long mixerBuffer = getNextMixerBuffer(); - if (mixerBuffer != 0) { - ByteBuffer buf = getMixerBufferData(mixerBuffer); - - if (buf == null) { - // This is happening on CVM because - // JNI_NewDirectByteBuffer isn't implemented - // by default and isn't compatible with the - // JSR-239 NIO implementation (apparently) - buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer), - getMixerBufferDataCapacity(mixerBuffer)); - } + mixerAlive = true; + try { + while (!shutdown) { + // Get the next buffer + final long mixerBuffer = getNextMixerBuffer(); + if (mixerBuffer != 0) { + ByteBuffer buf = getMixerBufferData(mixerBuffer); + + if (buf == null) { + // This is happening on CVM because + // JNI_NewDirectByteBuffer isn't implemented + // by default and isn't compatible with the + // JSR-239 NIO implementation (apparently) + buf = newDirectByteBuffer(getMixerBufferDataAddress(mixerBuffer), + getMixerBufferDataCapacity(mixerBuffer)); + } - if (buf == null) { - throw new InternalError("Couldn't wrap the native address with a direct byte buffer"); - } + if (buf == null) { + throw new InternalError("Couldn't wrap the native address with a direct byte buffer"); + } - // System.out.println("Mixing buffer"); + // System.out.println("Mixing buffer"); - // If we don't have enough samples in our mixing buffer, expand it - // FIXME: knowledge of native output rendering format - if ((mixingBuffer == null) || (mixingBuffer.length < (buf.capacity() / 2 /* bytes / sample */))) { - mixingBuffer = new float[buf.capacity() / 2]; - } else { - // Zap it - for (int i = 0; i < mixingBuffer.length; i++) { - mixingBuffer[i] = 0.0f; + // If we don't have enough samples in our mixing buffer, expand it + // FIXME: knowledge of native output rendering format + if ((mixingBuffer == null) || (mixingBuffer.length < (buf.capacity() / 2 /* bytes / sample */))) { + mixingBuffer = new float[buf.capacity() / 2]; + } else { + // Zap it + for (int i = 0; i < mixingBuffer.length; i++) { + mixingBuffer[i] = 0.0f; + } } - } - - // This assertion should be in place if we have stereo - if ((mixingBuffer.length % 2) != 0) { - final String msg = "FATAL ERROR: odd number of samples in the mixing buffer"; - System.out.println(msg); - throw new InternalError(msg); - } - // Run down all of the registered tracks mixing them in - final List<Track> curTracks = tracks; + // This assertion should be in place if we have stereo + if ((mixingBuffer.length % 2) != 0) { + final String msg = "FATAL ERROR: odd number of samples in the mixing buffer"; + System.out.println(msg); + throw new InternalError(msg); + } - for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) { - final Track track = iter.next(); - // Consider only playing tracks - if (track.isPlaying()) { - // First recompute its gain - final Vec3f pos = track.getPosition(); - final float leftGain = gain(pos, leftSpeakerPosition); - final float rightGain = gain(pos, rightSpeakerPosition); - // Now mix it in - int i = 0; - while (i < mixingBuffer.length) { - if (track.hasNextSample()) { - final float sample = track.nextSample(); - mixingBuffer[i++] = sample * leftGain; - mixingBuffer[i++] = sample * rightGain; - } else { - // This allows tracks to stall without being abruptly cancelled - if (track.done()) { - remove(track); + // Run down all of the registered tracks mixing them in + final List<Track> curTracks = tracks; + + for (final Iterator<Track> iter = curTracks.iterator(); iter.hasNext(); ) { + final Track track = iter.next(); + // Consider only playing tracks + if (track.isPlaying()) { + // First recompute its gain + final Vec3f pos = track.getPosition(); + final float leftGain = gain(pos, leftSpeakerPosition); + final float rightGain = gain(pos, rightSpeakerPosition); + // Now mix it in + int i = 0; + while (i < mixingBuffer.length) { + if (track.hasNextSample()) { + final float sample = track.nextSample(); + mixingBuffer[i++] = sample * leftGain; + mixingBuffer[i++] = sample * rightGain; + } else { + // This allows tracks to stall without being abruptly cancelled + if (track.done()) { + remove(track); + } + break; } - break; } } } - } - // Now that we have our data, send it down to the card - int outPos = 0; - for (int i = 0; i < mixingBuffer.length; i++) { - final short val = (short) mixingBuffer[i]; - buf.put(outPos++, (byte) val); - buf.put(outPos++, (byte) (val >> 8)); - } - if (!prepareMixerBuffer(mixerBuffer)) { - throw new RuntimeException("Error preparing mixer buffer"); - } - if (!writeMixerBuffer(mixerBuffer)) { - throw new RuntimeException("Error writing mixer buffer to device"); - } - } else { - // System.out.println("No mixer buffer available"); + // Now that we have our data, send it down to the card + int outPos = 0; + for (int i = 0; i < mixingBuffer.length; i++) { + final short val = (short) mixingBuffer[i]; + buf.put(outPos++, (byte) val); + buf.put(outPos++, (byte) (val >> 8)); + } + if (!prepareMixerBuffer(mixerBuffer)) { + throw new RuntimeException("Error preparing mixer buffer"); + } + if (!writeMixerBuffer(mixerBuffer)) { + throw new RuntimeException("Error writing mixer buffer to device"); + } + } else { + // System.out.println("No mixer buffer available"); - // Wait for a buffer to become available - if (!WaitForSingleObject(event)) { - throw new RuntimeException("Error while waiting for event object"); - } + // Wait for a buffer to become available + if (!WaitForSingleObject(event)) { + throw new RuntimeException("Error while waiting for event object"); + } - /* - try { - Thread.sleep(10); - } catch (InterruptedException e) { + /* + try { + Thread.sleep(10); + } catch (InterruptedException e) { + throw new InterruptedRuntimeException(e); + } + */ } - */ } - } - - // Need to shut down - shutdownWaveOut(); - synchronized(shutdownLock) { - shutdownLock.notifyAll(); + } finally { + mixerAlive = false; + // Need to shut down + shutdownWaveOut(); + synchronized(shutdownLock) { + shutdownLock.notifyAll(); + } } } diff --git a/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java b/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java index 9381d318b..9f885e55d 100644 --- a/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java +++ b/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java @@ -391,35 +391,16 @@ public class BuildComposablePipeline { final PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter(file))); - final List<Class<?>> baseInterfaces = Arrays.asList(baseInterfaceClass.getInterfaces()); - final HashSet<Class<?>> clazzList = new HashSet<Class<?>>(); - clazzList.add(baseInterfaceClass); - clazzList.addAll(baseInterfaces); - final int ifNamesNumber = clazzList.size(); - - // keep original order .. - clazzList.clear(); - final String[] ifNames = new String[ifNamesNumber]; - { - int i = 0; - - for (final Iterator<Class<?>> iter = baseInterfaces.iterator(); iter.hasNext();) { - final Class<?> ifClass = iter.next(); - if (!clazzList.contains(ifClass)) { - ifNames[i++] = ifClass.getName(); - clazzList.add(ifClass); - } - } + final HashSet<Class<?>> importClazzList = new HashSet<Class<?>>(); + importClazzList.add(baseInterfaceClass); + final String[] ifNames = new String[] { baseInterfaceClass.getName() }; - if ( !clazzList.contains(baseInterfaceClass) ) { - ifNames[i++] = baseInterfaceClass.getName(); - clazzList.add(baseInterfaceClass); - } - } + final List<Class<?>> baseInterfaces = Arrays.asList(baseInterfaceClass.getInterfaces()); + importClazzList.addAll(baseInterfaces); - clazzList.add(downstreamClass); + importClazzList.add(downstreamClass); if (null != prologClassOpt) { - clazzList.add(prologClassOpt); + importClazzList.add(prologClassOpt); } final ArrayList<String> imports = new ArrayList<String>(); @@ -427,7 +408,7 @@ public class BuildComposablePipeline { imports.add("com.jogamp.opengl.*"); imports.add("com.jogamp.gluegen.runtime.*"); imports.add(Buffer.class.getPackage().getName()+".*"); - for (final Class<?> clasS : clazzList) { + for (final Class<?> clasS : importClazzList) { imports.add(clasS.getName()); } diff --git a/src/jogl/classes/com/jogamp/gluegen/opengl/GLConfiguration.java b/src/jogl/classes/com/jogamp/gluegen/opengl/GLConfiguration.java index d6f72ee29..1c034ebfb 100644 --- a/src/jogl/classes/com/jogamp/gluegen/opengl/GLConfiguration.java +++ b/src/jogl/classes/com/jogamp/gluegen/opengl/GLConfiguration.java @@ -254,6 +254,14 @@ public class GLConfiguration extends ProcAddressConfiguration { super.logRenames(); } + protected boolean isIgnoredExtension(final String extensionName) { + if( ignoredExtensions.contains(extensionName) ) { + return !forcedExtensions.contains(extensionName); + } else { + return false; + } + } + protected boolean shouldIgnoreExtension(final AliasedSymbol symbol) { final Set<String> symExtensionNames; // collect current-name symbol extensions diff --git a/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java b/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java index 8df4a9488..a68fc6b2a 100644 --- a/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java +++ b/src/jogl/classes/com/jogamp/gluegen/opengl/GLEmitter.java @@ -112,31 +112,35 @@ public class GLEmitter extends ProcAddressEmitter { final Set<String> extensionSet = isSemHeader ? config.getExtensionsRenamedIntoCore() : glInfo.getExtensions(); for (final String extension : extensionSet) { - LOG.log(INFO, "<RenameExtensionIntoCore: {0} BEGIN {1}", extension, headerType); - final Set<String> declarations = glInfo.getDeclarations(extension); - if (declarations != null) { - for (final Iterator<String> iterator = declarations.iterator(); iterator.hasNext();) { - final String decl = iterator.next(); - final boolean isGLFunction = GLNameResolver.isGLFunction(decl); - boolean isGLEnumeration = false; - if (!isGLFunction) { - isGLEnumeration = GLNameResolver.isGLEnumeration(decl); - } - if (isGLFunction || isGLEnumeration) { - final String renamed = GLNameResolver.normalize(decl, isGLFunction); - if (!renamed.equals(decl)) { - if( isSemHeader ) { - // Sem + Doc - config.addJavaSymbolRename(decl, renamed); - } else { - // Doc only - config.addJavaDocSymbolRename(decl, renamed); + if( isSemHeader && config.isIgnoredExtension(extension) ) { + LOG.log(INFO, "<RenameExtensionIntoCore: {0} IGNORED {1}>", extension, headerType); + } else { + LOG.log(INFO, "<RenameExtensionIntoCore: {0} BEGIN {1}", extension, headerType); + final Set<String> declarations = glInfo.getDeclarations(extension); + if (declarations != null) { + for (final Iterator<String> iterator = declarations.iterator(); iterator.hasNext();) { + final String decl = iterator.next(); + final boolean isGLFunction = GLNameResolver.isGLFunction(decl); + boolean isGLEnumeration = false; + if (!isGLFunction) { + isGLEnumeration = GLNameResolver.isGLEnumeration(decl); + } + if (isGLFunction || isGLEnumeration) { + final String renamed = GLNameResolver.normalize(decl, isGLFunction); + if (!renamed.equals(decl)) { + if( isSemHeader ) { + // Sem + Doc + config.addJavaSymbolRename(decl, renamed); + } else { + // Doc only + config.addJavaDocSymbolRename(decl, renamed); + } } } } } + LOG.log(INFO, "RenameExtensionIntoCore: {0} END>", extension, headerType); } - LOG.log(INFO, "RenameExtensionIntoCore: {0} END>", extension, headerType); } } diff --git a/src/jogl/classes/com/jogamp/gluegen/runtime/opengl/GLNameResolver.java b/src/jogl/classes/com/jogamp/gluegen/runtime/opengl/GLNameResolver.java index d400381c8..d7e340630 100644 --- a/src/jogl/classes/com/jogamp/gluegen/runtime/opengl/GLNameResolver.java +++ b/src/jogl/classes/com/jogamp/gluegen/runtime/opengl/GLNameResolver.java @@ -50,27 +50,30 @@ public class GLNameResolver { private static final String[] extensionsARB = { "ARB", "GL2", "OES", "KHR", "OML" }; private static final String[] extensionsVEN = { "3DFX", "AMD", + "ANDROID", "ANGLE", "ARM", "APPLE", "ATI", "EXT", + "FJ", "HI", "HP", "IBM", "IMG", + "INGR", + "INTEL", "MESA", "MESAX", "NV", + "PGI", "QCOM", "SGI", "SGIS", "SGIX", "SUN", "VIV", - "WIN" - }; - + "WIN" }; public static final boolean isGLFunction(final String str) { return str.startsWith("gl") || /* str.startsWith("glu") || str.startsWith("glX") || */ diff --git a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java index be16e030f..76badcda8 100644 --- a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java +++ b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java @@ -199,7 +199,7 @@ public class FontFactory { throw new IOException(e); } } else { - stream = IOUtil.getResource(context, fname).getInputStream(); + stream = IOUtil.getResource(fname, context.getClassLoader(), context).getInputStream(); } if( null != stream ) { return FontFactory.get ( stream, true ) ; diff --git a/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java b/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java index 549efd569..38b8f770b 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java +++ b/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java @@ -58,7 +58,8 @@ public interface GLAnimatorControl extends FPSCounter { * Any exception thrown by this method will be ignored. * </p> * @param animator the {@link GLAnimatorControl} - * @param drawable the causing {@link GLAutoDrawable} + * @param drawable the causing {@link GLAutoDrawable}, + * may be {@code null} in case {@link Throwable} caused unrelated to any {@link GLAutoDrawable}. * @param cause the uncaught exception * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler) * @since 2.2 diff --git a/src/jogl/classes/com/jogamp/opengl/GLBase.java b/src/jogl/classes/com/jogamp/opengl/GLBase.java index dee5f1488..0cbcbe40f 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLBase.java +++ b/src/jogl/classes/com/jogamp/opengl/GLBase.java @@ -237,6 +237,19 @@ public interface GLBase { public boolean isGLES31Compatible(); /** + * Indicates whether this GL object is compatible with the core OpenGL ES3.2 functionality. + * <p> + * Return true if the underlying context is an ES3 context ≥ 3.2 or implements + * the extension <code>GL_ARB_ES3_2_compatibility</code>, otherwise false. + * </p> + * <p> + * Includes [ GL ≥ 4.5, GL ≥ 3.1 w/ GL_ARB_ES3_2_compatibility and GLES3 ≥ 3.2 ] + * </p> + * @see GLContext#isGLES32Compatible() + */ + public boolean isGLES32Compatible(); + + /** * Indicates whether this GL object supports GLSL. * @see GLContext#hasGLSL() */ @@ -446,29 +459,43 @@ public interface GLBase { public boolean isTextureFormatBGRA8888Available(); - /** 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 - causes the application to wait until the next vertical refresh - until swapping buffers. The default, which is platform-specific, - is usually either 0 or 1. This function is not guaranteed to - have an effect, and in particular only affects heavyweight - onscreen components. - - @see #getSwapInterval - @throws GLException if this context is not the current + /** + * Set the swap interval of the current context and attached <i>onscreen {@link GLDrawable}</i>. + * <p> + * <i>offscreen {@link GLDrawable}</i> are ignored and {@code false} is returned. + * </p> + * <p> + * The {@code interval} semantics: + * <ul> + * <li><i>0</i> disables the vertical synchronization</li> + * <li><i>≥1</i> is the number of vertical refreshes before a swap buffer occurs</li> + * <li><i><0</i> enables <i>late swaps to occur without synchronization to the video frame</i>, a.k.a <i>EXT_swap_control_tear</i>. + * If supported, the absolute value is the minimum number of + * video frames between buffer swaps. If not supported, the absolute value is being used, see above. + * </li> + * </ul> + * </p> + * @param interval see above + * @return true if the operation was successful, otherwise false + * @throws GLException if the context is not current. + * @see GLContext#setSwapInterval(int) + * @see #getSwapInterval() */ - public void setSwapInterval(int interval); + public void setSwapInterval(int interval) throws GLException; - /** Provides a platform-independent way to get the swap - interval set by {@link #setSwapInterval}. <br> - - If the interval is not set by {@link #setSwapInterval} yet, - -1 is returned, indicating that the platforms default - is being used. - - @see #setSwapInterval - */ + /** + * Return the current swap interval. + * <p> + * If the context has not been made current at all, + * the default value {@code 0} is returned. + * </p> + * <p> + * For a valid context w/ an <o>onscreen {@link GLDrawable}</i> the default value is {@code 1}, + * otherwise the default value is {@code 0}. + * </p> + * @see GLContext#getSwapInterval() + * @see #setSwapInterval(int) + */ public int getSwapInterval(); /** @@ -494,12 +521,12 @@ public interface GLBase { * for accessing it, including which class or interface contains the * functions. * - * <P> - * + * <p> * Note: it is the intent to add new extensions as quickly as possible * to the core GL API. Therefore it is unlikely that most vendors will * use this extension mechanism, but it is being provided for * completeness. + * </p> */ public Object getExtension(String extensionName); diff --git a/src/jogl/classes/com/jogamp/opengl/GLContext.java b/src/jogl/classes/com/jogamp/opengl/GLContext.java index f68c029df..606e4b4ed 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLContext.java +++ b/src/jogl/classes/com/jogamp/opengl/GLContext.java @@ -198,16 +198,19 @@ public abstract class GLContext { /** <code>GL_ARB_ES3_compatibility</code> implementation related: Context is compatible w/ ES3. Not a cache key. See {@link #isGLES3Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_IMPL_ES3_COMPAT = 1 << 11; - /** <code>GL_ARB_ES3_1_compatibility</code> implementation related: Context is compatible w/ ES3. Not a cache key. See {@link #isGLES31Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ + /** <code>GL_ARB_ES3_1_compatibility</code> implementation related: Context is compatible w/ ES 3.1. Not a cache key. See {@link #isGLES31Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ protected static final int CTX_IMPL_ES31_COMPAT = 1 << 12; + /** <code>GL_ARB_ES3_2_compatibility</code> implementation related: Context is compatible w/ ES 3.2. Not a cache key. See {@link #isGLES32Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */ + protected static final int CTX_IMPL_ES32_COMPAT = 1 << 13; + /** * Context supports basic FBO, details see {@link #hasBasicFBOSupport()}. * Not a cache key. * @see #hasBasicFBOSupport() * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile) */ - protected static final int CTX_IMPL_FBO = 1 << 13; + protected static final int CTX_IMPL_FBO = 1 << 14; /** * Context supports <code>OES_single_precision</code>, fp32, fixed function point (FFP) compatibility entry points, @@ -216,7 +219,7 @@ public abstract class GLContext { * @see #hasFP32CompatAPI() * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile) */ - protected static final int CTX_IMPL_FP32_COMPAT_API = 1 << 14; + protected static final int CTX_IMPL_FP32_COMPAT_API = 1 << 15; private static final ThreadLocal<GLContext> currentContext = new ThreadLocal<GLContext>(); @@ -237,7 +240,6 @@ public abstract class GLContext { protected String ctxVersionString; protected VersionNumberString ctxVendorVersion; protected VersionNumber ctxGLSLVersion; - private int currentSwapInterval; protected GLRendererQuirks glRendererQuirks; /** Did the drawable association changed ? see {@link GLRendererQuirks#NoSetSwapIntervalPostRetarget} */ @@ -258,7 +260,6 @@ public abstract class GLContext { ctxGLSLVersion = VersionNumber.zeroVersion; attachedObjects.clear(); contextHandle=0; - currentSwapInterval = -1; glRendererQuirks = null; drawableRetargeted = false; } @@ -925,6 +926,17 @@ public abstract class GLContext { } /** + * Return true if this context is an ES3 context ≥ 3.2 or implements + * the extension <code>GL_ARB_ES3_2_compatibility</code>, otherwise false. + * <p> + * Includes [ GL ≥ 4.5, GL ≥ 3.1 w/ GL_ARB_ES3_2_compatibility and GLES3 ≥ 3.2 ] + * </p> + */ + public final boolean isGLES32Compatible() { + return 0 != ( ctxOptions & CTX_IMPL_ES32_COMPAT ) ; + } + + /** * @return true if impl. is a hardware rasterizer, otherwise false. * @see #isHardwareRasterizer(AbstractGraphicsDevice, GLProfile) * @see GLProfile#isHardwareRasterizer() @@ -1182,8 +1194,9 @@ public abstract class GLContext { if( 0 != ( ctxOptions & CTX_PROFILE_ES ) ) { final int major = ctxVersion.getMajor(); return 2 == major || 3 == major; + } else { + return false; } - return false; } /** @@ -1246,49 +1259,55 @@ public abstract class GLContext { } /** - * Set the swap interval of the current context and attached drawable. - * @param interval Should be ≥ 0. 0 disables the vertical synchronization, - * where ≥ 1 is the number of vertical refreshes before a swap buffer occurs. - * A value < 0 is ignored. + * Set the swap interval of the current context and attached <i>onscreen {@link GLDrawable}</i>. + * <p> + * <i>offscreen {@link GLDrawable}</i> are ignored and {@code false} is returned. + * </p> + * <p> + * The {@code interval} semantics: + * <ul> + * <li><i>0</i> disables the vertical synchronization</li> + * <li><i>≥1</i> is the number of vertical refreshes before a swap buffer occurs</li> + * <li><i><0</i> enables <i>late swaps to occur without synchronization to the video frame</i>, a.k.a <i>EXT_swap_control_tear</i>. + * If supported, the absolute value is the minimum number of + * video frames between buffer swaps. If not supported, the absolute value is being used, see above. + * </li> + * </ul> + * </p> + * @param interval see above * @return true if the operation was successful, otherwise false - * * @throws GLException if the context is not current. + * @see #getSwapInterval() */ - public final boolean setSwapInterval(final int interval) throws GLException { - validateCurrent(); - if(0<=interval) { - if( !drawableRetargeted || !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget) ) { - if( setSwapIntervalImpl(interval) ) { - currentSwapInterval = interval; - return true; - } - } - } - return false; + public /* abstract */ boolean setSwapInterval(final int interval) throws GLException { + // FIXME: Make abstract for next version - just here to *not* break SEMVER! + throw new InternalError("Implemented in GLContextImpl"); } protected boolean setSwapIntervalImpl(final int interval) { - return false; + // FIXME: Remove for next version - just here to *not* break SEMVER! + throw new InternalError("Implemented in GLContextImpl"); } - /** Return the current swap interval. + + /** + * Return the current swap interval. * <p> * If the context has not been made current at all, - * the default value <code>-1</code> is returned. + * the default value {@code 0} is returned. * </p> * <p> - * For a valid context the default value is <code>1</code> - * in case of an EGL based profile (ES1 or ES2) and <code>-1</code> - * (undefined) for desktop. + * For a valid context w/ an <o>onscreen {@link GLDrawable}</i> the default value is {@code 1}, + * otherwise the default value is {@code 0}. * </p> + * @see #setSwapInterval(int) */ - public final int getSwapInterval() { - return currentSwapInterval; + public /* abstract */ int getSwapInterval() { + // FIXME: Make abstract for next version - just here to *not* break SEMVER! + throw new InternalError("Implemented in GLContextImpl"); } - protected final void setDefaultSwapInterval() { - if(this.isGLES()) { - currentSwapInterval = 1; - } else { - currentSwapInterval = -1; - } + + protected void setDefaultSwapInterval() { + // FIXME: Remove for next version - just here to *not* break SEMVER! + throw new InternalError("Implemented in GLContextImpl"); } public final boolean queryMaxSwapGroups(final int[] maxGroups, final int maxGroups_offset, @@ -1492,7 +1511,7 @@ public abstract class GLContext { /* 0.*/ { -1 }, /* 1.*/ { 0, 1 }, /* 2.*/ { 0 }, - /* 3.*/ { 0, 1 } }; + /* 3.*/ { 0, 1, 2 } }; public static final int getMaxMajor(final int ctxProfile) { return ( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) ? ES_VERSIONS.length-1 : GL_VERSIONS.length-1; @@ -1613,8 +1632,14 @@ public abstract class GLContext { ( ( b8 & 0x000000FF ) << 16 ) | ( ( c16 & 0x0000FFFF ) ) ; } + protected static VersionNumber decomposeBits(final int bits32, final int[] ctp) { + final int major = ( bits32 & 0xFF000000 ) >>> 24 ; + final int minor = ( bits32 & 0x00FF0000 ) >>> 16 ; + ctp[0] = ( bits32 & 0x0000FFFF ) ; + return new VersionNumber(major, minor, 0); + } - private static void validateProfileBits(final int bits, final String argName) { + protected static void validateProfileBits(final int bits, final String argName) { int num = 0; if( 0 != ( CTX_PROFILE_COMPAT & bits ) ) { num++; } if( 0 != ( CTX_PROFILE_CORE & bits ) ) { num++; } @@ -1660,7 +1685,7 @@ public abstract class GLContext { deviceVersionsAvailableSet.remove(devKey); } if (DEBUG) { - System.err.println(getThreadName() + ": createContextARB: SET mappedVersionsAvailableSet "+devKey); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions SET "+devKey); System.err.println(GLContext.dumpAvailableGLVersions(null).toString()); } } @@ -1675,38 +1700,6 @@ public abstract class GLContext { return r.intern(); } - /** - * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable(int,int)} not intended to be used by - * implementations. However, if {@link jogamp.opengl.GLContextImpl#createContextARB(long, boolean)} is not being used within - * {@link com.jogamp.opengl.GLDrawableFactory#getOrCreateSharedContext(com.jogamp.nativewindow.AbstractGraphicsDevice)}, - * GLProfile has to map the available versions. - * - * @param reqMajor Key Value either 1, 2, 3 or 4 - * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} - * @return the old mapped value - * - * @see #createContextARBMapVersionsAvailable - */ - protected static Integer mapAvailableGLVersion(final AbstractGraphicsDevice device, - final int reqMajor, final int profile, final int resMajor, final int resMinor, int resCtp) - { - validateProfileBits(profile, "profile"); - validateProfileBits(resCtp, "resCtp"); - - if(FORCE_NO_FBO_SUPPORT) { - resCtp &= ~CTX_IMPL_FBO ; - } - if(DEBUG) { - System.err.println("GLContext.mapAvailableGLVersion: "+device+": "+getGLVersion(reqMajor, 0, profile, null)+" -> "+getGLVersion(resMajor, resMinor, resCtp, null)); - // Thread.dumpStack(); - } - final String objectKey = getDeviceVersionAvailableKey(device, reqMajor, profile); - final Integer val = Integer.valueOf(composeBits(resMajor, resMinor, resCtp)); - synchronized(deviceVersionAvailable) { - return deviceVersionAvailable.put( objectKey, val ); - } - } - protected static StringBuilder dumpAvailableGLVersions(StringBuilder sb) { if(null == sb) { sb = new StringBuilder(); @@ -1714,19 +1707,17 @@ public abstract class GLContext { synchronized(deviceVersionAvailable) { final Set<String> keys = deviceVersionAvailable.keySet(); boolean needsSeparator = false; - for(final Iterator<String> i = keys.iterator(); i.hasNext(); ) { + for(final Iterator<String> keyI = keys.iterator(); keyI.hasNext(); ) { if(needsSeparator) { sb.append(Platform.getNewline()); } - final String key = i.next(); - sb.append(key).append(": "); + final String key = keyI.next(); + sb.append("MapGLVersions ").append(key).append(": "); final Integer valI = deviceVersionAvailable.get(key); if(null != valI) { - final int bits32 = valI.intValue(); - final int major = ( bits32 & 0xFF000000 ) >>> 24 ; - final int minor = ( bits32 & 0x00FF0000 ) >>> 16 ; - final int ctp = ( bits32 & 0x0000FFFF ) ; - sb.append(GLContext.getGLVersion(major, minor, ctp, null)); + final int[] ctp = { 0 }; + final VersionNumber version = decomposeBits(valI.intValue(), ctp); + GLContext.getGLVersion(sb, version, ctp[0], null); } else { sb.append("n/a"); } @@ -1949,15 +1940,7 @@ public abstract class GLContext { return isGLVersionAvailable(device, 3, GLContext.CTX_PROFILE_ES, isHardware); } - /** - * Returns true if a ES3 compatible profile is available, - * i.e. either a ≥ 4.3 context or a ≥ 3.1 context supporting <code>GL_ARB_ES3_compatibility</code>, - * otherwise false. - * <p> - * Includes [ GL ≥ 4.3, GL ≥ 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ] - * </p> - */ - public static final boolean isGLES3CompatibleAvailable(final AbstractGraphicsDevice device) { + private static final int getGL3ctp(final AbstractGraphicsDevice device) { final int major[] = { 0 }; final int minor[] = { 0 }; final int ctp[] = { 0 }; @@ -1970,7 +1953,19 @@ public abstract class GLContext { if( !ok ) { GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_COMPAT, major, minor, ctp); } - return 0 != ( ctp[0] & CTX_IMPL_ES3_COMPAT ); + return ctp[0]; + } + + /** + * Returns true if a ES3 compatible profile is available, + * i.e. either a ≥ 4.3 context or a ≥ 3.1 context supporting <code>GL_ARB_ES3_compatibility</code>, + * otherwise false. + * <p> + * Includes [ GL ≥ 4.3, GL ≥ 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ] + * </p> + */ + public static final boolean isGLES3CompatibleAvailable(final AbstractGraphicsDevice device) { + return 0 != ( getGL3ctp(device) & CTX_IMPL_ES3_COMPAT ); } /** * Returns true if a ES3 ≥ 3.1 compatible profile is available, @@ -1981,19 +1976,18 @@ public abstract class GLContext { * </p> */ public static final boolean isGLES31CompatibleAvailable(final AbstractGraphicsDevice device) { - final int major[] = { 0 }; - final int minor[] = { 0 }; - final int ctp[] = { 0 }; - boolean ok; - - ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_ES, major, minor, ctp); - if( !ok ) { - ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, major, minor, ctp); - } - if( !ok ) { - GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_COMPAT, major, minor, ctp); - } - return 0 != ( ctp[0] & CTX_IMPL_ES31_COMPAT ); + return 0 != ( getGL3ctp(device) & CTX_IMPL_ES31_COMPAT ); + } + /** + * Returns true if a ES3 ≥ 3.2 compatible profile is available, + * i.e. either a ≥ 4.5 context or a ≥ 3.1 context supporting <code>GL_ARB_ES3_2_compatibility</code>, + * otherwise false. + * <p> + * Includes [ GL ≥ 4.5, GL ≥ 3.1 w/ GL_ARB_ES3_2_compatibility and GLES3 ≥ 3.2 ] + * </p> + */ + public static final boolean isGLES32CompatibleAvailable(final AbstractGraphicsDevice device) { + return 0 != ( getGL3ctp(device) & CTX_IMPL_ES32_COMPAT ); } public static boolean isGL4bcAvailable(final AbstractGraphicsDevice device, final boolean isHardware[]) { @@ -2016,13 +2010,8 @@ public abstract class GLContext { return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT, isHardware); } - protected static String getGLVersion(final int major, final int minor, final int ctp, final String gl_version) { + protected static StringBuilder getGLProfile(final StringBuilder sb, final int ctp) { boolean needColon = false; - final StringBuilder sb = new StringBuilder(); - sb.append(major); - sb.append("."); - sb.append(minor); - sb.append(" ("); needColon = appendString(sb, "ES profile", needColon, 0 != ( CTX_PROFILE_ES & ctp )); needColon = appendString(sb, "Compat profile", needColon, 0 != ( CTX_PROFILE_COMPAT & ctp )); needColon = appendString(sb, "Core profile", needColon, 0 != ( CTX_PROFILE_CORE & ctp )); @@ -2035,6 +2024,7 @@ public abstract class GLContext { needColon = appendString(sb, "ES2", needColon, 0 != ( CTX_IMPL_ES2_COMPAT & ctp )); needColon = appendString(sb, "ES3", needColon, 0 != ( CTX_IMPL_ES3_COMPAT & ctp )); needColon = appendString(sb, "ES31", needColon, 0 != ( CTX_IMPL_ES31_COMPAT & ctp )); + needColon = appendString(sb, "ES32", needColon, 0 != ( CTX_IMPL_ES32_COMPAT & ctp )); needColon = appendString(sb, "FP32", needColon, 0 != ( CTX_IMPL_FP32_COMPAT_API & ctp )); needColon = false; } @@ -2045,12 +2035,26 @@ public abstract class GLContext { } else { needColon = appendString(sb, "hardware", needColon, true); } + return sb; + } + protected static StringBuilder getGLVersion(final StringBuilder sb, final VersionNumber version, final int ctp, final String gl_version) { + return getGLVersion(sb, version.getMajor(), version.getMinor(), ctp, gl_version); + } + protected static StringBuilder getGLVersion(final StringBuilder sb, final int major, final int minor, final int ctp, final String gl_version) { + sb.append(major); + sb.append("."); + sb.append(minor); + sb.append(" ("); + getGLProfile(sb, ctp); sb.append(")"); if(null!=gl_version) { sb.append(" - "); sb.append(gl_version); } - return sb.toString(); + return sb; + } + protected static String getGLVersion(final int major, final int minor, final int ctp, final String gl_version) { + return getGLVersion(new StringBuilder(), major, minor, ctp, gl_version).toString(); } // diff --git a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java index 7d78e3409..51da34ce0 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java @@ -421,6 +421,18 @@ public abstract class GLDrawableFactory { public abstract GLRendererQuirks getRendererQuirks(AbstractGraphicsDevice device, final GLProfile glp); /** + * Method returns {@code true} if underlying implementation may support native desktop OpenGL, + * otherwise {@code false}. + */ + public abstract boolean hasOpenGLDesktopSupport(); + + /** + * Method returns {@code true} if underlying implementation may support native embedded OpenGL ES, + * otherwise {@code false}. + */ + public abstract boolean hasOpenGLESSupport(); + + /** * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null */ public static GLDrawableFactory getDesktopFactory() { diff --git a/src/jogl/classes/com/jogamp/opengl/GLExtensions.java b/src/jogl/classes/com/jogamp/opengl/GLExtensions.java index 1bf8071ea..23e7dec31 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLExtensions.java +++ b/src/jogl/classes/com/jogamp/opengl/GLExtensions.java @@ -36,6 +36,7 @@ public class GLExtensions { public static final String VERSION_1_5 = "GL_VERSION_1_5"; public static final String VERSION_2_0 = "GL_VERSION_2_0"; + public static final String GL_KHR_debug = "GL_KHR_debug"; public static final String ARB_debug_output = "GL_ARB_debug_output"; public static final String AMD_debug_output = "GL_AMD_debug_output"; @@ -53,6 +54,7 @@ public class GLExtensions { public static final String ARB_ES2_compatibility = "GL_ARB_ES2_compatibility"; public static final String ARB_ES3_compatibility = "GL_ARB_ES3_compatibility"; public static final String ARB_ES3_1_compatibility = "GL_ARB_ES3_1_compatibility"; + public static final String ARB_ES3_2_compatibility = "GL_ARB_ES3_2_compatibility"; public static final String EXT_abgr = "GL_EXT_abgr"; public static final String OES_rgb8_rgba8 = "GL_OES_rgb8_rgba8"; diff --git a/src/jogl/classes/com/jogamp/opengl/GLProfile.java b/src/jogl/classes/com/jogamp/opengl/GLProfile.java index a36a21ad5..520db78ad 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLProfile.java +++ b/src/jogl/classes/com/jogamp/opengl/GLProfile.java @@ -39,6 +39,7 @@ package com.jogamp.opengl; import jogamp.opengl.Debug; import jogamp.opengl.GLDrawableFactoryImpl; +import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.DesktopGLDynamicLookupHelper; import com.jogamp.common.ExceptionUtils; @@ -242,7 +243,7 @@ public class GLProfile { initLock.unlock(); } if(DEBUG) { - if( justInitialized && ( hasGL234Impl || hasGLES1Impl || hasGLES3Impl ) ) { + if( justInitialized && ( hasGL234Impl || hasGL234OnEGLImpl || hasGLES1Impl || hasGLES3Impl ) ) { System.err.println(JoglVersion.getDefaultOpenGLInfo(defaultDevice, null, true)); } } @@ -1629,6 +1630,7 @@ public class GLProfile { private static /*final*/ boolean hasEGLFactory; private static /*final*/ boolean hasGLES3Impl; private static /*final*/ boolean hasGLES1Impl; + private static /*final*/ boolean hasGL234OnEGLImpl; private static /*final*/ Constructor<?> ctorGL234Impl; private static /*final*/ Constructor<?> ctorGLES3Impl; private static /*final*/ Constructor<?> ctorGLES1Impl; @@ -1681,6 +1683,7 @@ public class GLProfile { ctorGL234ProcAddr = null; } } + hasGL234OnEGLImpl = hasGL234Impl; // depends on hasEGLFactory { @@ -1745,10 +1748,9 @@ public class GLProfile { try { desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2); if(null != desktopFactory) { - final DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(GL2); - if(null!=glLookupHelper) { - hasDesktopGLFactory = glLookupHelper.isLibComplete() && hasGL234Impl; - } + final DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(2, GLContext.CTX_PROFILE_COMPAT); + hasGL234Impl = null!=glLookupHelper && glLookupHelper.isLibComplete() && hasGL234Impl; + hasDesktopGLFactory = hasGL234Impl; } } catch (final LinkageError le) { t=le; @@ -1780,10 +1782,14 @@ public class GLProfile { try { eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); if(null != eglFactory) { - hasEGLFactory = true; - // update hasGLES1Impl, hasGLES3Impl based on EGL - hasGLES3Impl = null!=eglFactory.getGLDynamicLookupHelper(GLES2) && hasGLES3Impl; - hasGLES1Impl = null!=eglFactory.getGLDynamicLookupHelper(GLES1) && hasGLES1Impl; + // update hasGLES1Impl, hasGLES3Impl, hasGL234OnEGLImpl based on library completion + final GLDynamicLookupHelper es2DynLookup = eglFactory.getGLDynamicLookupHelper(2, GLContext.CTX_PROFILE_ES); + final GLDynamicLookupHelper es1DynLookup = eglFactory.getGLDynamicLookupHelper(1, GLContext.CTX_PROFILE_ES); + final GLDynamicLookupHelper glXDynLookup = eglFactory.getGLDynamicLookupHelper(3, GLContext.CTX_PROFILE_CORE); + hasGLES3Impl = null!=es2DynLookup && es2DynLookup.isLibComplete() && hasGLES3Impl; + hasGLES1Impl = null!=es1DynLookup && es1DynLookup.isLibComplete() && hasGLES1Impl; + hasGL234OnEGLImpl = null!=glXDynLookup && glXDynLookup.isLibComplete() && hasGL234OnEGLImpl; + hasEGLFactory = hasGLES3Impl || hasGLES1Impl || hasGL234OnEGLImpl; } } catch (final LinkageError le) { t=le; @@ -1803,6 +1809,8 @@ public class GLProfile { final AbstractGraphicsDevice defaultEGLDevice; if(null == eglFactory) { + hasEGLFactory = false; + hasGL234OnEGLImpl= false; hasGLES3Impl = false; hasGLES1Impl = false; defaultEGLDevice = null; @@ -1843,6 +1851,7 @@ public class GLProfile { System.err.println("GLProfile.init hasEGLFactory "+hasEGLFactory); System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl); System.err.println("GLProfile.init hasGLES3Impl "+hasGLES3Impl); + System.err.println("GLProfile.init hasGL234OnEGLImpl "+hasGL234OnEGLImpl); System.err.println("GLProfile.init defaultDevice "+defaultDevice); System.err.println("GLProfile.init defaultDevice Desktop "+defaultDesktopDevice); System.err.println("GLProfile.init defaultDevice EGL "+defaultEGLDevice); @@ -1887,7 +1896,9 @@ public class GLProfile { return null != map.get(GL_DEFAULT); } + HashMap<String, GLProfile> mappedDesktopProfiles = null; boolean addedDesktopProfile = false; + HashMap<String, GLProfile> mappedEGLProfiles = null; boolean addedEGLProfile = false; final boolean deviceIsDesktopCompatible = hasDesktopGLFactory && desktopFactory.getIsDeviceCompatible(device); @@ -1906,21 +1917,23 @@ public class GLProfile { if(null != sharedResourceThread) { initLock.removeOwner(sharedResourceThread); } - if (DEBUG) { - System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail); - } - if(!desktopSharedCtxAvail) { - hasDesktopGLFactory = false; - } else if( !GLContext.getAvailableGLVersionsSet(device) ) { - throw new InternalError("Available GLVersions not set"); + if( desktopSharedCtxAvail ) { + if( !GLContext.getAvailableGLVersionsSet(device) ) { + throw new InternalError("Available GLVersions not set for "+device); + } + mappedDesktopProfiles = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); + addedDesktopProfile = mappedDesktopProfiles.size() > 0; + if (DEBUG) { + System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail+ + ", profiles: "+(addedDesktopProfile ? mappedDesktopProfiles.size() : 0)); + } } - addedDesktopProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); } final boolean deviceIsEGLCompatible = hasEGLFactory && eglFactory.getIsDeviceCompatible(device); // also test GLES1, GLES2 and GLES3 on desktop, since we have implementations / emulations available. - if( deviceIsEGLCompatible && ( hasGLES3Impl || hasGLES1Impl ) ) { + if( deviceIsEGLCompatible ) { // 1st pretend we have all EGL profiles .. computeProfileMap(device, true /* desktopCtxUndef*/, true /* esCtxUndef */); @@ -1934,18 +1947,17 @@ public class GLProfile { 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; - hasGLES3Impl = false; - hasGLES1Impl = false; + if( eglSharedCtxAvail ) { + if( !GLContext.getAvailableGLVersionsSet(device) ) { + throw new InternalError("Available GLVersions not set for "+device); + } + mappedEGLProfiles = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); + addedEGLProfile = mappedEGLProfiles.size() > 0; } if (DEBUG) { - System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail); + System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail+ + ", profiles: "+(addedEGLProfile ? mappedEGLProfiles.size() : 0)); } - addedEGLProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); } if( !addedDesktopProfile && !addedEGLProfile ) { @@ -1959,13 +1971,22 @@ public class GLProfile { System.err.println("GLProfile: hasGLES1Impl "+hasGLES1Impl); System.err.println("GLProfile: hasGLES3Impl "+hasGLES3Impl); } + } else { + final HashMap<String, GLProfile> mappedAllProfiles = new HashMap<String, GLProfile>(); + if( addedEGLProfile ) { + mappedAllProfiles.putAll(mappedEGLProfiles); + } + if( addedDesktopProfile ) { + mappedAllProfiles.putAll(mappedDesktopProfiles); + } + setProfileMap(device, mappedAllProfiles); // union } GLContext.setAvailableGLVersionsSet(device, true); if (DEBUG) { - System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": added profile(s): desktop "+addedDesktopProfile+", egl "+addedEGLProfile); - System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": "+glAvailabilityToString(device)); + System.err.println("GLProfile.initProfilesForDevice: "+device.getUniqueID()+": added profile(s): desktop "+addedDesktopProfile+", egl "+addedEGLProfile); + System.err.println("GLProfile.initProfilesForDevice: "+device.getUniqueID()+": "+glAvailabilityToString(device)); if(addedDesktopProfile) { dumpGLInfo(desktopFactory, device); final List<GLCapabilitiesImmutable> availCaps = desktopFactory.getAvailableCapabilities(device); @@ -1996,6 +2017,9 @@ public class GLProfile { } } else { System.err.println("GLProfile.dumpGLInfo: shared context n/a"); + System.err.println(device.getClass().getSimpleName()+"[type "+ + device.getType()+", connection "+device.getConnection()+"]:"); + System.err.println(GLProfile.glAvailabilityToString(device, null, "\t", 1).toString()); } } @@ -2026,9 +2050,9 @@ public class GLProfile { sb.append("]"); } - private static boolean computeProfileMap(final AbstractGraphicsDevice device, final boolean desktopCtxUndef, final boolean esCtxUndef) { + private static HashMap<String, GLProfile> computeProfileMap(final AbstractGraphicsDevice device, final boolean desktopCtxUndef, final boolean esCtxUndef) { if (DEBUG) { - System.err.println("GLProfile.init map "+device.getConnection()+", desktopCtxUndef "+desktopCtxUndef+", esCtxUndef "+esCtxUndef); + System.err.println("GLProfile.init map "+device.getUniqueID()+", desktopCtxUndef "+desktopCtxUndef+", esCtxUndef "+esCtxUndef); } final boolean isHardwareRasterizer[] = new boolean[1]; GLProfile defaultGLProfileAny = null; @@ -2050,22 +2074,22 @@ public class GLProfile { } _mappedProfiles.put(profile, glProfile); if (DEBUG) { - System.err.println("GLProfile.init map "+glProfile+" on device "+device.getConnection()); + System.err.println("GLProfile.init map "+glProfile+" on device "+device.getUniqueID()); } if( null == defaultGLProfileHW && isHardwareRasterizer[0] ) { defaultGLProfileHW=glProfile; if (DEBUG) { - System.err.println("GLProfile.init map defaultHW "+glProfile+" on device "+device.getConnection()); + System.err.println("GLProfile.init map defaultHW "+glProfile+" on device "+device.getUniqueID()); } } else if( null == defaultGLProfileAny ) { defaultGLProfileAny=glProfile; if (DEBUG) { - System.err.println("GLProfile.init map defaultAny "+glProfile+" on device "+device.getConnection()); + System.err.println("GLProfile.init map defaultAny "+glProfile+" on device "+device.getUniqueID()); } } } else { if (DEBUG) { - System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getConnection()); + System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getUniqueID()); } } } @@ -2075,13 +2099,14 @@ public class GLProfile { _mappedProfiles.put(GL_DEFAULT, defaultGLProfileAny); } setProfileMap(device, _mappedProfiles); - return _mappedProfiles.size() > 0; + return _mappedProfiles; } /** * Returns the profile implementation */ private static String computeProfileImpl(final AbstractGraphicsDevice device, final String profile, final boolean desktopCtxUndef, final boolean esCtxUndef, final boolean isHardwareRasterizer[]) { + final boolean hasAnyGL234Impl = hasGL234Impl || hasGL234OnEGLImpl; final boolean hardwareRasterizer[] = new boolean[1]; if ( GL2ES1 == profile ) { final boolean gles1Available; @@ -2093,7 +2118,7 @@ public class GLProfile { gles1Available = false; gles1HWAvailable = false; } - if(hasGL234Impl) { + if( hasAnyGL234Impl ) { final boolean gl3bcAvailable = GLContext.isGL3bcAvailable(device, hardwareRasterizer); final boolean gl3bcHWAvailable = gl3bcAvailable && hardwareRasterizer[0] ; final boolean gl2Available = GLContext.isGL2Available(device, hardwareRasterizer); @@ -2132,7 +2157,7 @@ public class GLProfile { gles3Available = false; gles3HWAvailable = false; } - if( hasGL234Impl ) { + if( hasAnyGL234Impl ) { final boolean gl4bcAvailable = GLContext.isGL4bcAvailable(device, hardwareRasterizer); final boolean gl4bcHWAvailable = gl4bcAvailable && hardwareRasterizer[0] ; final boolean gl3Available = GLContext.isGL3Available(device, hardwareRasterizer); @@ -2179,7 +2204,7 @@ public class GLProfile { final boolean es3HardwareRasterizer[] = new boolean[1]; final boolean gles3Available = hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, es3HardwareRasterizer) ); final boolean gles3HWAvailable = gles3Available && es3HardwareRasterizer[0] ; - if( hasGL234Impl ) { + if( hasAnyGL234Impl ) { final boolean gl4bcAvailable = GLContext.isGL4bcAvailable(device, hardwareRasterizer); final boolean gl4bcHWAvailable = gl4bcAvailable && hardwareRasterizer[0] ; final boolean glAnyHWAvailable = gl4bcHWAvailable || @@ -2200,7 +2225,7 @@ public class GLProfile { } } } else if(GL2GL3 == profile) { - if(hasGL234Impl) { + if( hasAnyGL234Impl ) { final boolean gl4Available = GLContext.isGL4Available(device, hardwareRasterizer); final boolean gl4HWAvailable = gl4Available && hardwareRasterizer[0] ; final boolean gl3Available = GLContext.isGL3Available(device, hardwareRasterizer); @@ -2232,15 +2257,15 @@ public class GLProfile { return GL2; } } - } else if(GL4bc == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) { + } else if(GL4bc == profile && hasAnyGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) { return desktopCtxUndef ? GL4bc : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_COMPAT); - } else if(GL4 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) { + } else if(GL4 == profile && hasAnyGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) { return desktopCtxUndef ? GL4 : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_CORE); - } else if(GL3bc == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) { + } else if(GL3bc == profile && hasAnyGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) { return desktopCtxUndef ? GL3bc : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_COMPAT); - } else if(GL3 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) { + } else if(GL3 == profile && hasAnyGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) { return desktopCtxUndef ? GL3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_CORE); - } else if(GL2 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) { + } else if(GL2 == profile && hasAnyGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) { return desktopCtxUndef ? GL2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_COMPAT); } else if(GLES3 == profile && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, isHardwareRasterizer))) { return esCtxUndef ? GLES3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_ES); diff --git a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java index 55c02d92a..7898566f3 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java +++ b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java @@ -287,6 +287,7 @@ public class GLRendererQuirks { * <li>EGL_VERSION 1.4</li> * <li>GL_VENDOR NVIDIA Corporation</li> * <li>GL_VERSION OpenGL ES 3.0 331.38 (probably w/ 1st NV EGL lib on x86)</li> + * <li>GL_VERSION OpenGL ES 3.1 NVIDIA 355.06 (unstable)</li> * <li>Platform X11</li> * <li>CPU Family {@link Platform.CPUFamily#X86}</li> * </ul> @@ -393,7 +394,7 @@ public class GLRendererQuirks { * </p> */ public static final int NeedSharedObjectSync = 20; - + /** * No reliable ARB_create_context implementation, * even if driver claims otherwise. @@ -401,8 +402,8 @@ public class GLRendererQuirks { * Some drivers wrongly claim to support ARB_create_context. * However, the creation of such context fails: * <pre> - * com.jogamp.opengl.GLException: AWT-EventQueue-0: WindowsWGLContex.createContextImpl ctx !ARB, profile > GL2 - * requested (OpenGL >= 3.0.1). Requested: GLProfile[GL3bc/GL3bc.hw], current: 2.1 (Compat profile, FBO, hardware) + * com.jogamp.opengl.GLException: AWT-EventQueue-0: WindowsWGLContex.createContextImpl ctx !ARB, profile > GL2 + * requested (OpenGL >= 3.0.1). Requested: GLProfile[GL3bc/GL3bc.hw], current: 2.1 (Compat profile, FBO, hardware) * - 2.1.8787 * </pre> * </p> diff --git a/src/jogl/classes/com/jogamp/opengl/GLUniformData.java b/src/jogl/classes/com/jogamp/opengl/GLUniformData.java index 44f7f29c7..55a2e0cf1 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLUniformData.java +++ b/src/jogl/classes/com/jogamp/opengl/GLUniformData.java @@ -84,6 +84,7 @@ public class GLUniformData { public IntBuffer intBufferValue() { return (IntBuffer)data; }; public FloatBuffer floatBufferValue() { return (FloatBuffer)data; }; + @SuppressWarnings("deprecation") public StringBuilder toString(StringBuilder sb) { if(null == sb) { sb = new StringBuilder(); diff --git a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java index 7589b3776..560d99025 100644 --- a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java +++ b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java @@ -144,8 +144,7 @@ public class JoglVersion extends JogampVersion { } sb.append(VersionUtil.SEPERATOR).append(Platform.getNewline()); - sb.append(device.getClass().getSimpleName()).append("[type ") - .append(device.getType()).append(", connection ").append(device.getConnection()).append("]: ").append(Platform.getNewline()); + sb.append(device.toString()).append(':').append(Platform.getNewline()); if( withAvailabilityInfo ) { GLProfile.glAvailabilityToString(device, sb, "\t", 1); } diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java index 5bf4c106c..20dc71958 100644 --- a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java @@ -98,6 +98,7 @@ import jogamp.opengl.awt.AWTTilePainter; import jogamp.opengl.awt.Java2D; import jogamp.opengl.util.glsl.GLSLTextureRaster; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.common.util.locks.LockFactory; @@ -395,7 +396,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing */ public final boolean initializeBackend(final boolean offthread) { if( offthread ) { - new Thread(getThreadName()+"-GLJPanel_Init") { + new InterruptSource.Thread(null, null, getThreadName()+"-GLJPanel_Init") { public void run() { if( !isInitialized ) { initializeBackendImpl(); diff --git a/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java b/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java index 8f033a8b8..d3f4c002d 100644 --- a/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java @@ -99,6 +99,16 @@ public final class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInf } @Override + public final boolean searchToolLibInSystemPath() { + return true; + } + + @Override + public final boolean searchToolLibSystemPathFirst() { + return true; + } + + @Override public final List<List<String>> getToolLibNames() { final List<List<String>> libsList = new ArrayList<List<String>>(); final List<String> libsCg = new ArrayList<String>(); diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java index 7f630f9d5..d24ca5b7e 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java @@ -1738,7 +1738,6 @@ public final class FloatUtil { * @param a 4x4 matrix in column-major order * @param b 4x4 matrix in column-major order * @param d result a*b in column-major order - * @deprecated use on of the float[] variants */ public static void multMatrix(final FloatBuffer a, final FloatBuffer b, final float[] d) { final int a_off = a.position(); @@ -1758,7 +1757,6 @@ public final class FloatUtil { * Multiply matrix: [a] = [a] x [b] * @param a 4x4 matrix in column-major order (also result) * @param b 4x4 matrix in column-major order - * @deprecated use on of the float[] variants */ public static void multMatrix(final FloatBuffer a, final FloatBuffer b) { final int a_off = a.position(); @@ -1831,7 +1829,6 @@ public final class FloatUtil { * @param m_in 4x4 matrix in column-major order * @param v_in 4-component column-vector * @param v_out m_in * v_in - * @deprecated use on of the float[] variants */ public static void multMatrixVec(final FloatBuffer m_in, final float[] v_in, final float[] v_out) { final int m_in_off = m_in.position(); @@ -1900,7 +1897,6 @@ public final class FloatUtil { * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @param row row number to print * @return matrix row string representation - * @deprecated use on of the float[] variants */ public static StringBuilder matrixRowToString(StringBuilder sb, final String f, final FloatBuffer a, final int aOffset, @@ -1959,7 +1955,6 @@ public final class FloatUtil { * @param columns * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @return matrix string representation - * @deprecated use on of the float[] variants */ public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, final FloatBuffer a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder) { @@ -2012,7 +2007,6 @@ public final class FloatUtil { * @param columns * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @return side by side representation - * @deprecated use on of the float[] variants */ public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, final FloatBuffer a, final int aOffset, final FloatBuffer b, final int bOffset, diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java index 76d64963f..9e9cc8e44 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java @@ -56,7 +56,7 @@ import com.jogamp.opengl.util.AnimatorBase.UncaughtAnimatorException; class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl { // For efficient rendering of Swing components, in particular when // they overlap one another - private final List<JComponent> lightweights = new ArrayList<JComponent>(); + private final List<JComponent> lightweights = new ArrayList<JComponent>(); private final Map<RepaintManager,RepaintManager> repaintManagers = new IdentityHashMap<RepaintManager,RepaintManager>(); private final Map<JComponent,Rectangle> dirtyRegions = new IdentityHashMap<JComponent,Rectangle>(); @@ -64,34 +64,40 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl { public void display(final ArrayList<GLAutoDrawable> drawables, final boolean ignoreExceptions, final boolean printExceptions) throws UncaughtAnimatorException { - for (int i=0; i<drawables.size(); i++) { - final GLAutoDrawable drawable = drawables.get(i); - if (drawable instanceof JComponent) { - // Lightweight components need a more efficient drawing - // scheme than simply forcing repainting of each one in - // turn since drawing one can force another one to be - // drawn in turn - lightweights.add((JComponent)drawable); - } else { - try { + boolean hasException = false; + for (int i=0; !hasException && i<drawables.size(); i++) { + GLAutoDrawable drawable = null; + boolean catch1 = true; + try { + drawable = drawables.get(i); + catch1 = false; + if (drawable instanceof JComponent) { + // Lightweight components need a more efficient drawing + // scheme than simply forcing repainting of each one in + // turn since drawing one can force another one to be + // drawn in turn + lightweights.add((JComponent)drawable); + } else { drawable.display(); - } catch (final Throwable t) { - if (ignoreExceptions) { - if (printExceptions) { - t.printStackTrace(); - } - } else { - throw new UncaughtAnimatorException(drawable, t); + } + } catch (final Throwable t) { + if( catch1 && t instanceof IndexOutOfBoundsException ) { + // concurrent pulling of GLAutoDrawables .. + hasException = true; + } else if ( ignoreExceptions ) { + if ( printExceptions ) { + t.printStackTrace(); } + } else { + throw new UncaughtAnimatorException(drawable, t); } } } - if (lightweights.size() > 0) { try { SwingUtilities.invokeAndWait(drawWithRepaintManagerRunnable); - } catch (final Exception e) { - e.printStackTrace(); + } catch (final Throwable t) { + t.printStackTrace(); } lightweights.clear(); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java index 066709316..10b0b6b5a 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java @@ -40,6 +40,9 @@ package com.jogamp.opengl.util; +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.SourcedInterruptedException; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLException; @@ -174,6 +177,9 @@ public class Animator extends AnimatorBase { try { Animator.this.wait(); } catch (final InterruptedException e) { + caughtException = new UncaughtAnimatorException(null, SourcedInterruptedException.wrap(e)); + stopIssued = true; + break; // end pause loop } if (wasPaused) { // resume from pause -> reset counter @@ -209,8 +215,7 @@ public class Animator extends AnimatorBase { } } catch(final ThreadDeath td) { if(DEBUG) { - System.err.println("Animator caught: "+td.getClass().getName()+": "+td.getMessage()); - td.printStackTrace(); + ExceptionUtils.dumpThrowable("", td); } caughtThreadDeath = td; } @@ -222,8 +227,7 @@ public class Animator extends AnimatorBase { if( null == caughtException ) { caughtException = dre; } else { - System.err.println("Animator.setExclusiveContextThread: caught: "+dre.getMessage()); - dre.printStackTrace(); + ExceptionUtils.dumpThrowable("(setExclusiveContextThread)", dre); } } } @@ -233,8 +237,7 @@ public class Animator extends AnimatorBase { if(DEBUG) { System.err.println("Animator stop on " + animThread.getName() + ": " + toString()); if( null != caughtException ) { - System.err.println("Animator caught: "+caughtException.getMessage()); - caughtException.printStackTrace(); + ExceptionUtils.dumpThrowable("", caughtException); } } stopIssued = false; @@ -291,13 +294,7 @@ public class Animator extends AnimatorBase { runnable = new MainLoop(); } fpsCounter.resetFPSCounter(); - final String threadName = getThreadName()+"-"+baseName; - Thread thread; - if(null==threadGroup) { - thread = new Thread(runnable, threadName); - } else { - thread = new Thread(threadGroup, runnable, threadName); - } + final Thread thread = new InterruptSource.Thread(threadGroup, runnable, getThreadName()+"-"+baseName); thread.setDaemon(false); // force to be non daemon, regardless of parent thread if(DEBUG) { final Thread ct = Thread.currentThread(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index aafdf63f8..41b969551 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -40,6 +40,7 @@ import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLProfile; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptedRuntimeException; /** * Base implementation of GLAnimatorControl<br> @@ -596,7 +597,9 @@ public abstract class AnimatorBase implements GLAnimatorControl { notifyAll(); try { wait(pollPeriod); - } catch (final InterruptedException ie) { } + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } remaining -= System.currentTimeMillis() - t1 ; nok = waitCondition.eval(); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java index 6cded29d9..d8c8465d9 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java @@ -48,12 +48,19 @@ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl { public void display(final ArrayList<GLAutoDrawable> drawables, final boolean ignoreExceptions, final boolean printExceptions) throws UncaughtAnimatorException { - for (int i=0; i<drawables.size(); i++) { - final GLAutoDrawable drawable = drawables.get(i); + boolean hasException = false; + for (int i=0; !hasException && i<drawables.size(); i++) { + boolean catch1 = true; + GLAutoDrawable drawable = null; try { + drawable = drawables.get(i); + catch1 = false; drawable.display(); } catch (final Throwable t) { - if (ignoreExceptions) { + if( catch1 && t instanceof IndexOutOfBoundsException ) { + // concurrent pulling of GLAutoDrawables .. + hasException = true; + } else if (ignoreExceptions) { if (printExceptions) { t.printStackTrace(); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java index c82f63898..0e3497bd4 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java @@ -262,6 +262,8 @@ public class GLPixelBuffer { case GL.GL_UNSIGNED_SHORT_5_5_5_1: pixFmt = PixelFormat.ABGR1555; break; + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: + // fall through intended case GL.GL_UNSIGNED_BYTE: pixFmt = PixelFormat.RGBA8888; break; @@ -280,6 +282,8 @@ public class GLPixelBuffer { case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: pixFmt = PixelFormat.ARGB8888; break; + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: + // fall through intended case GL.GL_UNSIGNED_BYTE: pixFmt = PixelFormat.BGRA8888; break; diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java index cc3462f99..3fa856a47 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java @@ -245,8 +245,8 @@ public class GLReadBufferUtil { readTexture.updateImage(gl, readTextureData); } else { readTexture.updateSubImage(gl, readTextureData, 0, - 0, 0, // src offset - 0, 0, // dst offset + inX, inY, // dst offset + 0, 0, // src offset width, height); } readPixelBuffer.rewind(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java index 196acf9ab..5383f91be 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java +++ b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java @@ -920,7 +920,6 @@ public final class PMVMatrix implements GLMatrixFunc { * or {@link #glGetFrustum() Frustum get} methods. * </p> * - * @deprecated Function is exposed for debugging purposes only. * @see #DIRTY_INVERSE_MODELVIEW * @see #DIRTY_INVERSE_TRANSPOSED_MODELVIEW * @see #DIRTY_FRUSTUM @@ -941,7 +940,6 @@ public final class PMVMatrix implements GLMatrixFunc { * or {@link #glGetFrustum() Frustum get} methods. * </p> * - * @deprecated Function is exposed for debugging purposes only. * @see #clearAllUpdateRequests() * @see #DIRTY_INVERSE_MODELVIEW * @see #DIRTY_INVERSE_TRANSPOSED_MODELVIEW diff --git a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java index f28774afa..1dded7882 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java +++ b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java @@ -78,7 +78,8 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { public static PNGPixelRect read(final InputStream in, final PixelFormat ddestFmt, final boolean destDirectBuffer, final int destMinStrideInBytes, final boolean destIsGLOriented) throws IOException { - final PngReader pngr = new PngReader(new BufferedInputStream(in), null); + final BufferedInputStream bin = (in instanceof BufferedInputStream) ? (BufferedInputStream)in : new BufferedInputStream(in); + final PngReader pngr = new PngReader(bin, null); final ImageInfo imgInfo = pngr.imgInfo; final PngChunkPLTE plte = pngr.getMetadata().getPLTE(); final PngChunkTRNS trns = pngr.getMetadata().getTRNS(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java index 662cf74b7..c2de32372 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java @@ -205,22 +205,29 @@ public interface GLMediaPlayer extends TextureSequence { * {@link Uri#scheme Uri scheme} name {@value} for camera input. E.g. <code>camera:/0</code> * for the 1st camera device. * <p> - * The {@link Uri#path Uri path} is being used to identify the camera (<i>ID</i>), + * The {@link Uri#path Uri path} is being used to identify the camera (<i><id></i>), * where the root fwd-slash is being cut-off. * </p> * <p> - * The <i>ID</i> is usually an integer value indexing the camera + * The <i><id></i> is usually an integer value indexing the camera * ranging from [0..<i>max-number</i>]. * </p> * <p> + * The <i><somewhere></i> is usually empty, since it would imply a networking camera protocol. + * </p> + * <p> * The {@link Uri#query Uri query} is used to pass options to the camera * using <i>;</i> as the separator. The latter avoids trouble w/ escaping. * </p> * <pre> - * camera:/<id> - * camera://somewhere/<id> - * camera://somewhere/<id>?width=640;height=480;rate=15 - * camera://somewhere/<id>?size=640x480;rate=15 + * camera:/<id> + * camera:/<id>?width=640;height=480;rate=15 + * camera:/<id>?size=640x480;rate=15 + * camera://<somewhere>/<id> + * camera://<somewhere>/<id>?width=640;height=480;rate=15 + * camera://<somewhere>/<id>?size=640x480;rate=15 + * camera:///<id>?width=640;height=480;rate=15 + * camera:///<id>?size=640x480;rate=15 * </pre> * <pre> * Uri: [scheme:][//authority][path][?query][#fragment] diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java index e6f5aaa2e..38bac06cc 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java @@ -40,6 +40,7 @@ package com.jogamp.opengl.util.awt; import com.jogamp.common.nio.Buffers; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.PropertyAccess; import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.util.*; @@ -915,7 +916,7 @@ public class TextRenderer { // Run this on another thread than the AWT event queue to // make sure the call to Animator.stop() completes before // exiting - new Thread(new Runnable() { + new InterruptSource.Thread(null, new Runnable() { @Override public void run() { anim.stop(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java index e1db3f7a3..532db3a7a 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java @@ -47,6 +47,7 @@ import java.util.Set; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GL3; +import com.jogamp.opengl.GL3ES3; import com.jogamp.opengl.GL4; import com.jogamp.opengl.GLES2; import com.jogamp.opengl.GLContext; @@ -87,6 +88,18 @@ public class ShaderCode { public static final String SUFFIX_GEOMETRY_BINARY = "bgp" ; /** + * Unique resource suffix for {@link GL3ES3#GL_COMPUTE_SHADER} in source code: <code>{@value}</code> + * @since 2.3.2 + */ + public static final String SUFFIX_COMPUTE_SOURCE = "cp" ; + + /** + * Unique resource suffix for {@link GL3ES3#GL_COMPUTE_SHADER} in binary: <code>{@value}</code> + * @since 2.3.2 + */ + public static final String SUFFIX_COMPUTE_BINARY = "bcp" ; + + /** * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in source code: <code>{@value}</code> * @since 2.2.1 */ @@ -121,7 +134,7 @@ public class ShaderCode { /** * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param source CharSequence array containing the shader sources, organized as <code>source[count][strings-per-shader]</code>. * May be either an immutable <code>String</code> - or mutable <code>StringBuilder</code> array. @@ -135,9 +148,10 @@ public class ShaderCode { switch (type) { case GL2ES2.GL_VERTEX_SHADER: case GL2ES2.GL_FRAGMENT_SHADER: - case GL3.GL_GEOMETRY_SHADER: - case GL3.GL_TESS_CONTROL_SHADER: - case GL3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_GEOMETRY_SHADER: + case GL3ES3.GL_TESS_CONTROL_SHADER: + case GL3ES3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_COMPUTE_SHADER: break; default: throw new GLException("Unknown shader type: "+type); @@ -157,7 +171,7 @@ public class ShaderCode { /** * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param binary binary buffer containing the shader binaries, */ @@ -165,9 +179,10 @@ public class ShaderCode { switch (type) { case GL2ES2.GL_VERTEX_SHADER: case GL2ES2.GL_FRAGMENT_SHADER: - case GL3.GL_GEOMETRY_SHADER: - case GL3.GL_TESS_CONTROL_SHADER: - case GL3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_GEOMETRY_SHADER: + case GL3ES3.GL_TESS_CONTROL_SHADER: + case GL3ES3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_COMPUTE_SHADER: break; default: throw new GLException("Unknown shader type: "+type); @@ -186,7 +201,7 @@ public class ShaderCode { * * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed. * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param context class used to help resolving the source location * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code> @@ -233,7 +248,7 @@ public class ShaderCode { * * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed. * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param sourceLocations array of {@link Uri} source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code> * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance @@ -279,7 +294,7 @@ public class ShaderCode { * which location is resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}. * * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param context class used to help resolving the source location * @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}. @@ -310,7 +325,7 @@ public class ShaderCode { * Creates a complete {@link ShaderCode} object while reading the shader binary from {@link Uri} <code>binLocations</code> * via {@link #readShaderBinary(Uri)}. * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}. * @param binLocations {@link Uri} binary location @@ -346,6 +361,7 @@ public class ShaderCode { * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_SOURCE}</li> * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_SOURCE}</li> * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_SOURCE}</li> + * <li>{@link GL3ES3#GL_COMPUTE_SHADER}: {@link #SUFFIX_COMPUTE_SOURCE}</li> * </ul></li> * <li>Binary<ul> * <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_BINARY}</li> @@ -353,11 +369,12 @@ public class ShaderCode { * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_BINARY}</li> * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_BINARY}</li> * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_BINARY}</li> + * <li>{@link GL3ES3#GL_COMPUTE_SHADER}: {@link #SUFFIX_COMPUTE_BINARY}</li> * </ul></li> * </ul> * @param binary true for a binary resource, false for a source resource * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * * @throws GLException if <code>type</code> is not supported * @@ -369,12 +386,14 @@ public class ShaderCode { return binary?SUFFIX_VERTEX_BINARY:SUFFIX_VERTEX_SOURCE; case GL2ES2.GL_FRAGMENT_SHADER: return binary?SUFFIX_FRAGMENT_BINARY:SUFFIX_FRAGMENT_SOURCE; - case GL3.GL_GEOMETRY_SHADER: + case GL3ES3.GL_GEOMETRY_SHADER: return binary?SUFFIX_GEOMETRY_BINARY:SUFFIX_GEOMETRY_SOURCE; - case GL3.GL_TESS_CONTROL_SHADER: + case GL3ES3.GL_TESS_CONTROL_SHADER: return binary?SUFFIX_TESS_CONTROL_BINARY:SUFFIX_TESS_CONTROL_SOURCE; - case GL3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_TESS_EVALUATION_SHADER: return binary?SUFFIX_TESS_EVALUATION_BINARY:SUFFIX_TESS_EVALUATION_SOURCE; + case GL3ES3.GL_COMPUTE_SHADER: + return binary?SUFFIX_COMPUTE_BINARY:SUFFIX_COMPUTE_SOURCE; default: throw new GLException("illegal shader type: "+type); } @@ -457,7 +476,7 @@ public class ShaderCode { * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used), * or to determine the shader binary format (if <code>binary</code> is used). * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param context class used to help resolving the source and binary location * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional @@ -591,7 +610,7 @@ public class ShaderCode { * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used), * or to determine the shader binary format (if <code>binary</code> is used). * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param count number of shaders * @param context class used to help resolving the source and binary location * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional @@ -659,7 +678,7 @@ public class ShaderCode { * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used), * or to determine the shader binary format (if <code>binary</code> is used). * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param context class used to help resolving the source and binary location * @param srcRoot relative <i>root</i> path for <code>basename</code> optional * @param binRoot relative <i>root</i> path for <code>basename</code> @@ -726,11 +745,16 @@ public class ShaderCode { * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used), * or to determine the shader binary format (if <code>binary</code> is used). * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, - * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}. * @param context class used to help resolving the source and binary location * @param srcRoot relative <i>root</i> path for <code>basename</code> optional * @param binRoot relative <i>root</i> path for <code>basename</code> - * @param mutableStringBuilder TODO + * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance + * which can be edited later on at the costs of a String conversion when passing to + * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. + * If <code>false</code> method returns an immutable <code>String</code> instance, + * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)} + * at no additional costs. * @param basenames basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code> * for the shader's source and binary code. * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance @@ -761,12 +785,14 @@ public class ShaderCode { return "VERTEX_SHADER"; case GL2ES2.GL_FRAGMENT_SHADER: return "FRAGMENT_SHADER"; - case GL3.GL_GEOMETRY_SHADER: + case GL3ES3.GL_GEOMETRY_SHADER: return "GEOMETRY_SHADER"; - case GL3.GL_TESS_CONTROL_SHADER: + case GL3ES3.GL_TESS_CONTROL_SHADER: return "TESS_CONTROL_SHADER"; - case GL3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_TESS_EVALUATION_SHADER: return "TESS_EVALUATION_SHADER"; + case GL3ES3.GL_COMPUTE_SHADER: + return "COMPUTE_SHADER"; } return "UNKNOWN_SHADER"; } @@ -1072,7 +1098,15 @@ public class ShaderCode { while ((line = reader.readLine()) != null) { lineno++; if (line.startsWith("#include ")) { - final String includeFile = line.substring(9).trim(); + final String includeFile; + { + String s = line.substring(9).trim(); + // Bug 1283: Remove shader include filename quotes if exists at start and end only + if( s.startsWith("\"") && s.endsWith("\"")) { + s = s.substring(1, s.length()-1); + } + includeFile = s; + } URLConnection nextConn = null; // Try relative of current shader location @@ -1080,7 +1114,7 @@ public class ShaderCode { nextConn = IOUtil.openURL(relUri.toURL(), "ShaderCode.relativeOf "); if (nextConn == null) { // Try relative of class and absolute - nextConn = IOUtil.getResource(context, includeFile); + nextConn = IOUtil.getResource(includeFile, context.getClassLoader(), context); } if (nextConn == null) { // Fail @@ -1132,7 +1166,7 @@ public class ShaderCode { * @see IOUtil#getResource(Class, String) */ public static CharSequence readShaderSource(final Class<?> context, final String path, final boolean mutableStringBuilder) throws IOException { - final URLConnection conn = IOUtil.getResource(context, path); + final URLConnection conn = IOUtil.getResource(path, context.getClassLoader(), context); if (conn == null) { return null; } @@ -1178,7 +1212,7 @@ public class ShaderCode { * @see IOUtil#getResource(Class, String) */ public static ByteBuffer readShaderBinary(final Class<?> context, final String path) throws IOException { - final URLConnection conn = IOUtil.getResource(context, path); + final URLConnection conn = IOUtil.getResource(path, context.getClassLoader(), context); if (conn == null) { return null; } @@ -1284,6 +1318,8 @@ public class ShaderCode { defaultPrecision = es3_default_precision_vp; break; case GL2ES2.GL_FRAGMENT_SHADER: defaultPrecision = es3_default_precision_fp; break; + case GL3ES3.GL_COMPUTE_SHADER: + defaultPrecision = es3_default_precision_fp; break; default: defaultPrecision = null; break; @@ -1302,12 +1338,14 @@ public class ShaderCode { // GLSL [ 1.30 .. 1.50 [ needs at least fragement float default precision! switch ( shaderType ) { case GL2ES2.GL_VERTEX_SHADER: - case GL3.GL_GEOMETRY_SHADER: - case GL3.GL_TESS_CONTROL_SHADER: - case GL3.GL_TESS_EVALUATION_SHADER: + case GL3ES3.GL_GEOMETRY_SHADER: + case GL3ES3.GL_TESS_CONTROL_SHADER: + case GL3ES3.GL_TESS_EVALUATION_SHADER: defaultPrecision = gl3_default_precision_vp_gp; break; case GL2ES2.GL_FRAGMENT_SHADER: defaultPrecision = gl3_default_precision_fp; break; + case GL3ES3.GL_COMPUTE_SHADER: + defaultPrecision = gl3_default_precision_fp; break; default: defaultPrecision = null; break; diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java index f5dec1cab..376afb8ce 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java @@ -52,7 +52,7 @@ public abstract class CompileShader { final String justName = basename(resourceName); outName = justName.substring(0, justName.length() - suffixLen) + ShaderCode.getFileSuffix(true, type); - final URL resourceURL = IOUtil.getResource(null, resourceName).getURL(); + final URL resourceURL = IOUtil.getResource(resourceName, this.getClass().getClassLoader(), null).getURL(); final String dirName = dirname(resourceURL.getPath()); outName = dirName + File.separator + "bin" + File.separator + @@ -64,7 +64,7 @@ public abstract class CompileShader { public void processOneShader(final String resourceName, final String outName, final int type) throws IOException, UnsupportedEncodingException, InterruptedException { - final URL resourceURL = IOUtil.getResource(null, resourceName).getURL(); + final URL resourceURL = IOUtil.getResource(resourceName, this.getClass().getClassLoader(), null).getURL(); final String dirName = dirname(resourceURL.getPath()); final CharSequence shader = ShaderCode.readShaderSource(null, resourceName, false); diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageIOUtil.java b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageIOUtil.java deleted file mode 100644 index 1e50f843d..000000000 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageIOUtil.java +++ /dev/null @@ -1,445 +0,0 @@ -/** - * Copyright 2014 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.util.texture; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Utilities for image input and output - * - */ -public class ImageIOUtil { - - /** - * Determines the file suffix (i.e the image format) of the given InputStream. The given - * InputStream must return true from markSupported() and support a minimum of 32 bytes - * of read-ahead. - * - * @param stream stream to check - * @return the file suffix if any, otherwise <code>null</code> - * @throws java.io.IOException if an I/O exception occurred - */ - public static String getFileSuffix(InputStream stream) throws IOException { - if (stream == null) { - throw new IOException("Stream was null"); - } - if (!(stream instanceof BufferedInputStream)) { - stream = new BufferedInputStream(stream); - } - if (!stream.markSupported()) { - throw new IOException("Can not get non-destructively the image format"); - } - if (stream.available() < 32) { - throw new IOException("Not enough bytes to read in order to get the image format"); - } - try { - stream.mark(32); - final byte[] b = new byte[32]; - stream.read(b); - return getFileSuffix(b); - } finally { - stream.reset(); - } - - } - - /** - * Determines the file suffix (i.e the image format) of the given bytes from the header - * of a file. - * - * @param stream stream to check - * @return the file suffix if any, otherwise <code>null</code> - * @throws java.io.IOException if an I/O exception occurred - */ - public static String getFileSuffix(final byte[] b) { - /** - * http://www.faqs.org/faqs/jpeg-faq/part1/ - * http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=54989 - */ - if ((b[0] == 0xff && b[1] == 0xd8 /* && b[2] == 0xff */) - || (b[0] == 0x4A && b[1] == 0x46 && b[2] == 0x49 && b[3] == 0x46)/* JFIF */ - || (b[0] == 0x45 && b[1] == 0x78 && b[2] == 0x69 && b[3] == 0x66)/* EXIF */) { - return TextureIO.JPG; - } - /** - * http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html#R.PNG-file-signature - */ - if (b[0] == 0x89 && b[1] == 0x50 && b[2] == 0x4E && b[3] == 0x47 /* 'P' 'N' 'G', ascii code */ - && b[4] == 0x0D && b[5] == 0x0A && b[6] == 0x1A && b[7] == 0x0A) { - return TextureIO.PNG; - } - /** - * Apple Icon Image - * - * 'i' 'c' 'n' 's' ascii code - */ - if (b[0] == 0x69 && b[1] == 0x63 && b[2] == 0x6E && b[3] == 0x73) { - return "icns"; - } - /** - * http://www.w3.org/Graphics/GIF/spec-gif87a.txt http://www.w3.org/Graphics/GIF/spec-gif89a.txt - * - * GIF87A or GIF89A ascii code - */ - if (b[0] == 0x47 && b[1] == 0x49 && b[2] == 0x46 && b[3] == 0x38 && (b[4] == 0x37 || b[4] == 0x39) - && b[5] == 0x61) { - return TextureIO.GIF; - } - /** - * http://www.fileformat.info/format/bmp/spec/e27073c25463436f8a64fa789c886d9c/view.htm - * - * BM ascii code - */ - if (b[0] == 0x42 && b[1] == 0x4d) { - return "bmp"; - } - if (b[0] == 0x3A && b[1] == 0xDE && b[2] == 0x68 && b[3] == 0xB1) { - return "dcx"; - } - if (b[0] == 0x0A && b[1] == 0x05 && b[2] == 0x01 && b[3] == 0x08) { - return "pcx"; - } - /** - * http://netpbm.sourceforge.net/doc/ppm.html - */ - if (b[0] == 0x50 && (b[1] == 0x33 /* plain */|| b[1] == 0x36)) { - return TextureIO.PPM; - } - if (b[0] == 0x38 && b[1] == 0x42 && b[2] == 0x50 && b[3] == 0x53 && b[4] == 0x00 && b[5] == 0x01 - && b[6] == 0x00 && b[7] == 0x00 && b[8] == 0x00 && b[9] == 0x00) { - // Adobe PhotoShop - return "psd"; - } - /** - * http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf - * - * intentionally detects only the little endian tiff images ("II" in the spec) - */ - if (b[0] == 0x49 && b[1] == 0x49 && b[2] == 0x2A && b[3] == 0x00) { - return TextureIO.TIFF; - } - /** - * http://paulbourke.net/dataformats/sgirgb/sgiversion.html - * - * "474 saved as a short" 474 = 0x01DA - */ - if (b[0] == 0x01 && b[1] == 0xDA /* && b[2] == 0x01 && b[3] == 0x01 && b[4] == 0x00 && b[5] == 0x03 */) { - return TextureIO.SGI_RGB; - } - /** - * 'D' 'D' 'S' ' ' ascii code - */ - if (b[0] == 0x44 && b[1] == 0x44 && b[2] == 0x53 && b[3] == 0x20) { - return TextureIO.DDS; - } - /** - * http://netpbm.sourceforge.net/doc/pam.html - */ - if (b[0] == 0x50 && b[1] == 0x37) { - return TextureIO.PAM; - } - /** - * http://netpbm.sourceforge.net/doc/pgm.html - */ - if (b[0] == 0x50 && (b[1] == 0x32 /* plain */|| b[1] == 0x35)) { - return "pgm"; - } - /** - * http://netpbm.sourceforge.net/doc/pbm.html - */ - if (b[0] == 0x50 && (b[1] == 0x31 /* plain */|| b[1] == 0x34)) { - return "pbm"; - } - if (b[0] == 0x3D && b[1] == 0x02) { - return "3d2"; - } - if (b[0] == 0x33 && b[1] == 0x44 && b[2] == 0x4D && b[3] == 0x46) { - return "3dmf"; - } - if (b[0] == 0x2A && b[1] == 0x2A && b[2] == 0x54 && b[3] == 0x49 && b[4] == 0x39 && b[5] == 0x32 - && b[6] == 0x2A && b[7] == 0x2A && b[8] == 0x01 && b[9] == 0x00 && b[10] == 0x58 - && b[11] == 0x6E && b[12] == 0x56 && b[13] == 0x69) { - return "92i"; - } - if (b[0] == 0x41 && b[1] == 0x4D && b[2] == 0x46 && b[3] == 0x46) { - return "amff"; - } - if (b[0] == 0x4A && b[1] == 0x47 && (b[2] == 0x03 || b[2] == 0x04) && b[3] == 0x0E && b[4] == 0x00 - && b[5] == 0x00 && b[6] == 0x00) { - return "art"; - } - if (b[0] == 0x73 && b[1] == 0x72 && b[2] == 0x63 && b[3] == 0x64 && b[4] == 0x6F && b[5] == 0x63 - && b[6] == 0x69 && b[7] == 0x64 && b[8] == 0x3A) { - return "cals"; - } - if (b[0] == 0x07 && b[1] == 0x20 && b[2] == 0x4D && b[3] == 0x4D) { - return "cam"; - } - if (b[0] == 0x20 && b[1] == 0x77 && b[2] == 0x00 && b[3] == 0x02) { - return "cbd"; - } - if (b[0] == 0x45 && b[1] == 0x59 && b[2] == 0x45 && b[3] == 0x53) { - return "ce2"; - } - if (b[0] == 0x80 && b[1] == 0x2A && b[2] == 0x5F && b[3] == 0xD7 && b[4] == 0x00 && b[5] == 0x00 - && b[6] == 0x08 && b[7] == 0x00 && b[8] == 0x00 && b[9] == 0x00 && b[10] == 0x04 - && b[11] == 0x00 && b[12] == 0x00 && b[13] == 0x00) { - return "cin"; - } - if (b[0] == 0x43 && b[1] == 0x61 && b[2] == 0x6C && b[3] == 0x69 && b[4] == 0x67 && b[5] == 0x61 - && b[6] == 0x72 && b[7] == 0x69) { - return "cob"; - } - if (b[0] == 0x43 && b[1] == 0x50 && b[2] == 0x54 && b[3] == 0x46 && b[4] == 0x49 && b[5] == 0x4C - && b[6] == 0x45) { - return "cpt"; - } - if (b[0] == 0x43 && b[1] == 0x41 && b[2] == 0x4C && b[3] == 0x41 && b[4] == 0x4D && b[5] == 0x55 - && b[6] == 0x53 && b[7] == 0x43 && b[8] == 0x56 && b[9] == 0x47) { - return "cvg"; - } - if (b[0] == 0x56 && b[1] == 0x69 && b[2] == 0x73 && b[3] == 0x74 && b[4] == 0x61 && b[5] == 0x20 - && b[6] == 0x44 && b[7] == 0x45 && b[8] == 0x4D && b[9] == 0x20 && b[10] == 0x46 - && b[11] == 0x69 && b[12] == 0x6C && b[13] == 0x65) { - return "dem"; - } - if (b[0] == 0x42 && b[1] == 0x4D && b[2] == 0x36) { - return "dib"; - } - if (b[0] == 0x53 && b[1] == 0x44 && b[2] == 0x50 && b[3] == 0x58) { - return "dpx"; - } - if (b[0] == 0x01 && b[1] == 0xFF && b[2] == 0x02 && b[3] == 0x04 && b[4] == 0x03 && b[5] == 0x02) { - return "drw"; - } - if (b[0] == 0x41 && b[1] == 0x43 && b[2] == 0x31 && b[3] == 0x30) { - return "dwg"; - } - if (b[0] == 0x65 && b[1] == 0x02 && b[2] == 0x01 && b[3] == 0x02) { - return "ecw"; - } - if (b[0] == 0x01 && b[1] == 0x00 && b[2] == 0x00 && b[3] == 0x00 && b[4] == 0x58 && b[5] == 0x00 - && b[6] == 0x00 && b[7] == 0x00) { - return "emf"; - } - if (b[0] == 0xD0 && b[1] == 0xCF && b[2] == 0x11 && b[3] == 0xE0 && b[4] == 0xA1 && b[5] == 0xB1 - && b[6] == 0x1A && b[7] == 0xE1 && b[8] == 0x00) { - return "fpx"; - } - if (b[0] == 0x53 && b[1] == 0x49 && b[2] == 0x4D && b[3] == 0x50 && b[4] == 0x4C && b[5] == 0x45 - && b[6] == 0x20 && b[7] == 0x20 && b[8] == 0x3D) { - return "fts"; - } - if (b[0] == 0x48 && b[1] == 0x50 && b[2] == 0x48 && b[3] == 0x50 && b[4] == 0x34 && b[5] == 0x38 - && b[6] == 0x2D && b[7] == 0x45 && b[8] == 0x1E && b[9] == 0x2B) { - return "gro"; - } - if (b[0] == 0x6E && b[1] == 0x63 && b[2] == 0x6F && b[3] == 0x6C && b[4] == 0x73) { - return "hdr"; - } - if (b[0] == 0x35 && b[1] == 0x4B && b[2] == 0x50 && b[3] == 0x35 && b[4] == 0x31 && b[5] == 0x5D - && b[6] == 0x2A && b[7] == 0x67 && b[8] == 0x72 && b[9] == 0x72 && b[10] == 0x80 - && b[11] == 0x83 && b[12] == 0x85 && b[13] == 0x63) { - return "hru"; - } - if (b[0] == 0xEB && b[1] == 0x3C && b[2] == 0x90 && b[3] == 0x2A) { - return "img"; - } - if (b[0] == 0x65 && b[1] == 0x6C && b[2] == 0x6D && b[3] == 0x6F) { - return "infini-d"; - } - if (b[0] == 0x49 && b[1] == 0x57 && b[2] == 0x43 && b[3] == 0x01) { - return "iwc"; - } - if (b[0] == 0x80 && b[1] == 0x3E && b[2] == 0x44 && b[3] == 0x53 && b[4] == 0x43 && b[5] == 0x49 - && b[6] == 0x4D) { - return "j6i"; - } - if (b[0] == 0x4A && b[1] == 0x49 && b[2] == 0x46 && b[3] == 0x39 && b[4] == 0x39 && b[5] == 0x61) { - return "jif"; - } - if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x00 && b[3] == 0x0C && b[4] == 0x6A && b[5] == 0x50 - && b[6] == 0x20 && b[7] == 0x20 && b[8] == 0x0D && b[9] == 0x0A && b[10] == 0x87 - && b[11] == 0x0A) { - return "jp2"; - } - if (b[0] == 0x4D && b[1] == 0x4D && b[2] == 0x00 && b[3] == 0x2A) { - return "kdc"; - } - if (b[0] == 0x36 && b[1] == 0x34 && b[2] == 0x4C && b[3] == 0x41 && b[4] == 0x4E && b[5] == 0x20 - && b[6] == 0x49 && b[7] == 0x44 && b[8] == 0x42 && b[9] == 0x4C && b[10] == 0x4F - && b[11] == 0x43 && b[12] == 0x4B) { - return "l64"; - } - if (b[0] == 0x46 && b[1] == 0x4F && b[2] == 0x52 && b[3] == 0x4D) { - return "lbm"; - } - if (b[0] == 0x49 && b[1] == 0x49 && b[2] == 0x2A && b[3] == 0x00 && b[4] == 0x08 && b[5] == 0x00 - && b[6] == 0x00 && b[7] == 0x00 && b[8] == 0x0E && b[9] == 0x00 && b[10] == 0x00 - && b[11] == 0x01 && b[12] == 0x04 && b[13] == 0x00) { - return "ldf"; - } - if (b[0] == 0x57 && b[1] == 0x56 && b[2] == 0x02 && b[3] == 0x00 && b[4] == 0x47 && b[5] == 0x45 - && b[6] == 0x00 && b[7] == 0x0E) { - return "lwf"; - } - if (b[0] == 0x37 && b[1] == 0x00 && b[2] == 0x00 && b[3] == 0x10 && b[4] == 0x42 && b[5] == 0x00 - && b[6] == 0x00 && b[7] == 0x10 && b[8] == 0x00 && b[9] == 0x00 && b[10] == 0x00 - && b[11] == 0x00 && b[12] == 0x39 && b[13] == 0x64) { - return "mbm"; - } - if (b[0] == 0x4D && b[1] == 0x47 && b[2] == 0x4C) { - return "mgl"; - } - if (b[0] == 0x7B && b[1] == 0x0A && b[2] == 0x20 && b[3] == 0x20 && b[4] == 0x43 && b[5] == 0x72 - && b[6] == 0x65 && b[7] == 0x61 && b[8] == 0x74 && b[9] == 0x65 && b[10] == 0x64) { - return "mif"; - } - if (b[0] == 0x8A && b[1] == 0x4D && b[2] == 0x4E && b[3] == 0x47 && b[4] == 0x0D && b[5] == 0x0A - && b[6] == 0x1A && b[7] == 0x0A) { - return "mng"; - } - if (b[0] == 0x4D && b[1] == 0x50 && b[2] == 0x46) { - return "mpw"; - } - if (b[0] == 0x44 && b[1] == 0x61 && b[2] == 0x6E && b[3] == 0x4D) { - return "msp"; - } - if (b[0] == 0x43 && b[1] == 0x36 && b[2] == 0x34) { - return "n64"; - } - if (b[0] == 0x6E && b[1] == 0x6E && b[2] == 0x0A && b[3] == 0x00 && b[4] == 0x5E && b[5] == 0x00) { - return "ncr"; - } - if (b[0] == 0x6E && b[1] == 0x66 && b[2] == 0x66) { - return "nff"; - } - if (b[0] == 0x4E && b[1] == 0x47 && b[2] == 0x47 && b[3] == 0x00 && b[4] == 0x01 && b[5] == 0x00) { - return "ngg"; - } - if (b[0] == 0x4E && b[1] == 0x4C && b[2] == 0x4D && b[3] == 0x20 && b[4] == 0x01 && b[5] == 0x02 - && b[6] == 0x00) { - return "nlm"; - } - if (b[0] == 0x4E && b[1] == 0x4F && b[2] == 0x4C && b[3] == 0x00 && b[4] == 0x01 && b[5] == 0x00 - && b[6] == 0x06 && b[7] == 0x01 && b[8] == 0x03 && b[9] == 0x00) { - return "nol"; - } - if (b[0] == 0x41 && b[1] == 0x48) { - return "pal"; - } - if (b[0] == 0x50 && b[1] == 0x41 && b[2] == 0x58) { - return "pax"; - } - if (b[0] == 0x63 && b[1] == 0x52 && b[2] == 0x01 && b[3] == 0x01 && b[4] == 0x38 && b[5] == 0x09 - && b[6] == 0x3D && b[7] == 0x00) { - return "pcd"; - } - if (b[0] == 0x1B && b[1] == 0x45 && b[2] == 0x1B && b[3] == 0x26 && b[4] == 0x6C && b[5] == 0x30 - && b[6] == 0x4F && b[7] == 0x1B && b[8] == 0x26 && b[9] == 0x6C && b[10] == 0x30 - && b[11] == 0x45 && b[12] == 0x1B && b[13] == 0x26) { - return "pcl"; - } - if (b[0] == 0x50 && b[1] == 0x49 && b[2] == 0x58 && b[3] == 0x20) { - return "pix"; - } - if (b[0] == 0x50 && b[1] == 0x4F && b[2] == 0x4C && b[3] == 0x20 && b[4] == 0x46 && b[5] == 0x6F - && b[6] == 0x72 && b[7] == 0x6D && b[8] == 0x61 && b[9] == 0x74) { - return "pol"; - } - // Paint Shop Pro - if (b[0] == 0x7E && b[1] == 0x42 && b[2] == 0x4B && b[3] == 0x00) { - return "psp"; - } - if (b[0] == 0x50 && b[1] == 0x61 && b[2] == 0x69 && b[3] == 0x6E && b[4] == 0x74 && b[5] == 0x20 - && b[6] == 0x53 && b[7] == 0x68 && b[8] == 0x6F && b[9] == 0x70 && b[10] == 0x20 - && b[11] == 0x50 && b[12] == 0x72 && b[13] == 0x6F && b[14] == 0x20 && b[15] == 0x49 - && b[16] == 0x6D && b[17] == 0x61 && b[18] == 0x67 && b[19] == 0x65 && b[20] == 0x20 - && b[21] == 0x46 && b[22] == 0x69 && b[23] == 0x6C && b[24] == 0x65) { - return "psp"; - } - if (b[0] == 0x51 && b[1] == 0x4C && b[2] == 0x49 && b[3] == 0x49 && b[4] == 0x46 && b[5] == 0x41 - && b[6] == 0x58) { - return "qfx"; - } - if (b[0] == 0x6D && b[1] == 0x6F && b[2] == 0x6F && b[3] == 0x76) { - return "qtm"; - } - if (b[0] == 0x46 && b[1] == 0x4F && b[2] == 0x52 && b[3] == 0x4D && b[4] == 0x41 && b[5] == 0x54 - && b[6] == 0x3D) { - return "rad"; - } - if (b[0] == 0x59 && b[1] == 0xA6 && b[2] == 0x6A && b[3] == 0x95) { - return "ras"; - } - if (b[0] == 0x52 && b[1] == 0x49 && b[2] == 0x58 && b[3] == 0x33) { - return "rix"; - } - if (b[0] == 0x23 && b[1] == 0x20 && b[2] == 0x24 && b[3] == 0x49 && b[4] == 0x64 && b[5] == 0x3A - && b[6] == 0x20) { - return "sid"; - } - if (b[0] == 0x41 && b[1] == 0x75 && b[2] == 0x74 && b[3] == 0x6F && b[4] == 0x43 && b[5] == 0x41 - && b[6] == 0x44 && b[7] == 0x20 && b[8] == 0x53 && b[9] == 0x6C && b[10] == 0x69 - && b[11] == 0x64 && b[12] == 0x65) { - return "sld"; - } - if (b[0] == 0x53 && b[1] == 0x74 && b[2] == 0x6F && b[3] == 0x72 && b[4] == 0x6D && b[5] == 0x33 - && b[6] == 0x44) { - return "sod"; - } - if (b[0] == 0xFA && b[1] == 0xDE && b[2] == 0xBA && b[3] == 0xBE && b[4] == 0x01 && b[5] == 0x01) { - return "wic"; - } - if (b[0] == 0xD3 && b[1] == 0x23 && b[2] == 0x00 && b[3] == 0x00 && b[4] == 0x03 && b[5] == 0x00 - && b[6] == 0x00 && b[7] == 0x00) { - return "wlm"; - } - if (b[0] == 0xD7 && b[1] == 0xCD && b[2] == 0xC6 && b[3] == 0x9A) { - return "wmf"; - } - if (b[0] == 0xFF && b[1] == 0x57 && b[2] == 0x50 && b[3] == 0x43 && b[4] == 0x10) { - return "wpg"; - } - if (b[0] == 0x23 && b[1] == 0x56 && b[2] == 0x52 && b[3] == 0x4D && b[4] == 0x4C && b[5] == 0x20 - && b[6] == 0x56 && b[7] == 0x32 && b[8] == 0x2E && b[9] == 0x30) { - return "wrl"; - } - if (b[0] == 0x23 && b[1] == 0x64 && b[2] == 0x65 && b[3] == 0x66 && b[4] == 0x69 && b[5] == 0x6E - && b[6] == 0x65) { - return "xbm"; - } - if (b[0] == 0x2F && b[1] == 0x2A && b[2] == 0x20 && b[3] == 0x58 && b[4] == 0x50 && b[5] == 0x4D - && b[6] == 0x20 && b[7] == 0x2A && b[8] == 0x2F) { - return "xpm"; - } - return null; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java index 0f51c2e14..e485e5452 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java @@ -77,7 +77,7 @@ public class ImageSequence implements TextureSequence { } public final void addFrame(final GL gl, final Class<?> context, final String imageResourcePath, final String imageSuffix) throws IOException { - final URLConnection urlConn = IOUtil.getResource(context, imageResourcePath); + final URLConnection urlConn = IOUtil.getResource(imageResourcePath, context.getClassLoader(), context); if(null != urlConn) { final TextureData texData = TextureIO.newTextureData(GLProfile.getGL2ES2(), urlConn.getInputStream(), false, imageSuffix); final Texture tex = new Texture(getTextureTarget()); diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageType.java b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageType.java new file mode 100644 index 000000000..8a3bae554 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageType.java @@ -0,0 +1,1579 @@ +/** + * Copyright 2014 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.util.texture; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Image type classification. + * <p> + * Allows to classify the {@link ImageType} of an {@link InputStream} via {@link #ImageType(InputStream)} + * or to simply define one {@link ImageType} via {@link #ImageType(String)}. + * </p> + * @since 2.3.2 + */ +public class ImageType { + /** + * Minimum number of bytes to determine the image data type, i.e. {@value} bytes. + */ + public static final int MAGIC_MAX_SIZE = 25; + + /** + * Constant which can be used as a file suffix to indicate a JPEG stream, value {@value}. + * <ul> + * <li>{@code http://www.faqs.org/faqs/jpeg-faq/part1/}</li> + * <li>{@code http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=54989}</li> + * </ul> + */ + public static final String T_JPG = "jpg"; + + /** + * Constant which can be used as a file suffix to indicate a PNG stream, value {@value}. + * <ul> + * <li>{@code http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html#R.PNG-file-signature}</li> + * </ul> + */ + public static final String T_PNG = "png"; + + /** + * Constant which can be used as a file suffix to indicate an Apple Icon Image stream, value {@value}. + * <p> + * {@code 'i' 'c' 'n' 's' ascii code} + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_ICNS = "icns"; + + /** + * Constant which can be used as a file suffix to indicate a Microsoft Windows Icon stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code https://msdn.microsoft.com/en-us/library/ms997538.aspx}</li> + * </ul> + */ + public static final String T_ICO = "ico"; + + /** + * Constant which can be used as a file suffix to indicate a Microsoft Windows Cursor stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_CUR = "cur"; + + /** + * Constant which can be used as a file suffix to indicate a GIF stream, value {@value}. + * <p> + * {@code GIF87A or GIF89A ascii code} + * </p> + * <ul> + * <li>{@code http://www.w3.org/Graphics/GIF/spec-gif87a.txt http://www.w3.org/Graphics/GIF/spec-gif89a.txt}</li> + * </ul> + */ + public static final String T_GIF = "gif"; + + /** + * Constant which can be used as a file suffix to indicate a GIF stream, value {@value}. + * <p> + * {@code BM ascii code} + * </p> + * <p> + * FIXME: Collision or supertype of {@link #T_DIB}? + * </p> + * <ul> + * <li>{@code http://www.fileformat.info/format/bmp/spec/e27073c25463436f8a64fa789c886d9c/view.htm}</li> + * </ul> + */ + public static final String T_BMP = "bmp"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * FIXME: Collision or subtype of {@link #T_BMP}? + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_DIB = "dib"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_DCX = "dcx"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PCX = "pcx"; + + /** + * Constant which can be used as a file suffix to indicate a PAM stream, NetPbm magic 6 - binary RGB. + * <ul> + * <li>{@code http://netpbm.sourceforge.net/doc/ppm.html}</li> + * </ul> + */ + public static final String T_PPM = "ppm"; + + /** + * Constant which can be used as a file suffix to indicate a Adobe PhotoShop stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PSD = "psd"; + + /** + * Constant which can be used as a file suffix to indicate a TIFF stream, value {@value}. + * <p> + * Intentionally detects only the little endian tiff images ("II" in the spec). + * </p> + * <p> + * FIXME: Collision or supertype of {@link #T_LDF}? + * </p> + * <ul> + * <li>{@code http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf}</li> + * </ul> + */ + public static final String T_TIFF = "tiff"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * FIXME: Collision or subtype of {@link #T_TIFF}? + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_LDF = "ldf"; + + /** + * Constant which can be used as a file suffix to indicate an SGI RGB stream, value {@value}. + * <p> + * "474 saved as a short" 474 = 0x01DA + * </p> + * <ul> + * <li>{@code http://paulbourke.net/dataformats/sgirgb/sgiversion.html}</li> + * </ul> + */ + public static final String T_SGI_RGB = "rgb"; + + /** + * Constant which can be used as a file suffix to indicate a DirectDraw Surface stream, value {@value}. + * <p> + * 'D' 'D' 'S' ' ' ascii code + * </p> + * <ul> + * <li>{@code https://msdn.microsoft.com/en-us/library/windows/desktop/bb943991%28v=vs.85%29.aspx#File_Layout1}</li> + * </ul> + */ + public static final String T_DDS = "dds"; + + /** + * Constant which can be used as a file suffix to indicate a Portable Arbitrary Map stream, NetPbm magic 7 - binary RGB and RGBA. + * <ul> + * <li>{@code http://netpbm.sourceforge.net/doc/pam.html}</li> + * </ul> + */ + public static final String T_PAM = "pam"; + + /** + * Constant which can be used as a file suffix to indicate a PGM stream, NetPbm magic 5 - binary grayscale. + * <ul> + * <li>{@code http://netpbm.sourceforge.net/doc/pgm.html}</li> + * </ul> + */ + public static final String T_PGM = "pgm"; + + /** + * Constant which can be used as a file suffix to indicate a PGM stream, NetPbm magic 4 - binary monochrome. + * <ul> + * <li>{@code http://netpbm.sourceforge.net/doc/pbm.html}</li> + * </ul> + */ + public static final String T_PBM = "pbm"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_3D2 = "3d2"; + + /** + * Constant which can be used as a file suffix to indicate an Apple QuickDraw 3D 3DMF stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_3DMF = "3dmf"; + + /** + * Constant which can be used as a file suffix to indicate a Texas Instruments TI-92 Bitmap stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_92I = "92i"; + + /** + * Constant which can be used as a file suffix to indicate an Amiga metafile stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_AMFF = "amff"; + + /** + * Constant which can be used as a file suffix to indicate an America Online Art stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_ART = "art"; + + /** + * Constant which can be used as a file suffix to indicate a United States Department of Defence Continuous Acquisition and Life-cycle Support Raster stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code http://www.fileformat.info/format/cals/egff.htm}</li> + * </ul> + */ + public static final String T_CALS = "cals"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_CAM = "cam"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_CBD = "cbd"; + + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_CE2 = "ce2"; + + /** + * Constant which can be used as a file suffix to indicate a Kodak Cineon System stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code http://www.cineon.com/ff_draft.php}</li> + * </ul> + */ + public static final String T_CIN = "cin"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_COB = "cob"; + + /** + * Constant which can be used as a file suffix to indicate a Corel Photo Paint stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_CPT = "cpt"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_CVG = "cvg"; + + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_DEM = "dem"; + + /** + * Constant which can be used as a file suffix to indicate a Digital Picture Exchange stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_DPX = "dpx"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_DRW = "drw"; + + /** + * Constant which can be used as a file suffix to indicate a Autocad drawing stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_DWG = "dwg"; + + /** + * Constant which can be used as a file suffix to indicate a Hexagon Geospatial Enhanced Compression Wavelet stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_ECW = "ecw"; + + /** + * Constant which can be used as a file suffix to indicate a Microsoft Windows Enhanced metafile stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_EMF = "emf"; + + /** + * Constant which can be used as a file suffix to indicate a FlashPix stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_FPX = "fpx"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_FTS = "fts"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_GRO = "gro"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_HDR = "hdr"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_HRU = "hru"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_IMG = "img"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_INFINI_D = "infini-d"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_IWC = "iwc"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_J6I = "j6i"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_JIF = "jif"; + + /** + * Constant which can be used as a file suffix to indicate a JPEG-2000 stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_JP2 = "jp2"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_KDC = "kdc"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_L64 = "l64"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * FIXME: Collision or supertype of {@link #T_RAD}? + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_LBM = "lbm"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * FIXME: Collision or subtype of {@link #T_LBM}? + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_RAD = "rad"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_LWF = "lwf"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_MBM = "mbm"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_MGL = "mgl"; + + /** + * Constant which can be used as a file suffix to indicate an Imagemagick stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_MIF = "mif"; + + /** + * Constant which can be used as a file suffix to indicate a Multiple-image Network Graphics stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_MNG = "mng"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_MPW = "mpw"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_MSP = "msp"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_N64 = "n64"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_NCR = "ncr"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_NFF = "nff"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_NGG = "ngg"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_NLM = "nlm"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_NOL = "nol"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PAL = "pal"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PAX = "pax"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PCD = "pcd"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PCL = "pcl"; + + /** + * Constant which can be used as a file suffix to indicate a Softimage pic stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code http://paulbourke.net/dataformats/softimagepic/}</li> + * </ul> + */ + public static final String T_PIC = "pic"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PIX = "pix"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_POL = "pol"; + + /** + * Constant which can be used as a file suffix to indicate a PaintShop Pro stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_PSP = "psp"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_QFX = "qfx"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_QTM = "qtm"; + + /** + * Constant which can be used as a file suffix to indicate a Sun Raster stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_RAS = "ras"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_RIX = "rix"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_SID = "sid"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_SLD = "sld"; + + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_SOD = "sod"; + + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_WIC = "wic"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_WLM = "wlm"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_WMF = "wmf"; + + /** + * Constant which can be used as a file suffix to indicate a Wordperfect Graphics vectors stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_WPG = "wpg"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_WRL = "wrl"; + + /** + * Constant which can be used as a file suffix to indicate a {@code TBD} stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_XBM = "xbm"; + + /** + * Constant which can be used as a file suffix to indicate a X PixMap stream, value {@value}. + * <p> + * TODO + * </p> + * <ul> + * <li>{@code TODO}</li> + * </ul> + */ + public static final String T_XPM = "xpm"; + + /** + * Constant which can be used as a file suffix to indicate a Targa stream, value {@value}. + * <ul> + * <li>{@code }</li> + * </ul> + */ + public static final String T_TGA = "tga"; + + /** + * The determined unique type, e.g. {@link #T_PNG}, {@link #T_JPG}, etc. + * <p> + * Maybe {@code null} if undetermined, i.e. {@link #isDefined()} returns {@code false}. + * </p> + */ + public final String type; + + /** + * The optionally read header of size {@link #MAGIC_MAX_SIZE} bytes as used to determine the {@link #type}, + * i.e. {@link #ImageType(InputStream)}. + * <p> + * May be {@code null}, if {@link #type} has been determined otherwise, i.e {@link #ImageType(String)}. + * </p> + * <p> + * The header is <i>not</i> being used for {@link #hashCode()} and {@link #equals(Object)}! + * </p> + */ + public final byte[] header; + + private final int hash; + + /** + * Creates instance based on given stream. + * @param stream stream to parse, {@link InputStream#available()} must be ≥ {@link #MAGIC_MAX_SIZE} + * @throws java.io.IOException if an I/O exception occurred + */ + public ImageType(final InputStream stream) throws IOException { + final byte[] _header = new byte[MAGIC_MAX_SIZE]; + type = Util.getFileSuffix(stream, _header); + this.header = _header; + this.hash = null != this.type ? this.type.hashCode() : 0; + } + /** + * Creates instance based on the given type. + * @param type must be one of {@link #T_PNG}, {@link #T_JPG}, etc. + */ + public ImageType(final String type) { + this.header = null; + this.type = type; + this.hash = this.type.hashCode(); + } + /** Returns {@code true} if {@link #type} is determined, i.e. not {@code null}, otherwise {@code false}. */ + public final boolean isDefined() { return null != type; } + + @Override + public final int hashCode() { + return hash; + } + @Override + public boolean equals(final Object o) { + if( o == this ) { + return true; + } else if( o instanceof ImageType ) { + final ImageType t = (ImageType)o; + return this.type.equals(t.type); + } else { + return false; + } + } + @Override + public String toString() { return "ImageType["+type+"]"; } + + /** + * Static utility functions for {@link ImageType} + * to determine the {@link ImageType#type}. + * @since 2.3.2 + */ + public static class Util { + /** + * Determines the file suffix (i.e the image format) of the given InputStream. The given + * InputStream must return true from markSupported() and support a minimum of {@link #MAGIC_MAX_SIZE} bytes + * of read-ahead. + * + * @param stream stream to parse, {@link InputStream#available()} must be ≥ {@link #MAGIC_MAX_SIZE} + * @return the file suffix if any, otherwise <code>null</code> + * @throws java.io.IOException if an I/O exception occurred + */ + public static String getFileSuffix(final InputStream stream) throws IOException { + return getFileSuffix(stream, new byte[MAGIC_MAX_SIZE]); + } + /** + * Determines the file suffix (i.e the image format) of the given InputStream. The given + * InputStream must return true from markSupported() and support a minimum of {@link #MAGIC_MAX_SIZE} bytes + * of read-ahead. + * + * @param stream stream to parse, {@link InputStream#available()} must be ≥ {@link #MAGIC_MAX_SIZE} + * @param b byte array sink, size must be ≥ {@link #MAGIC_MAX_SIZE} + * @return the file suffix if any, otherwise <code>null</code> + * @throws java.io.IOException if an I/O exception occurred + */ + public static String getFileSuffix(InputStream stream, final byte[] b) throws IOException { + if (stream == null) { + throw new IOException("Stream was null"); + } + if (!(stream instanceof BufferedInputStream)) { + stream = new BufferedInputStream(stream); + } + if (!stream.markSupported()) { + throw new IOException("Mark not supported"); + } + if (stream.available() < MAGIC_MAX_SIZE) { + throw new IOException("Requires "+MAGIC_MAX_SIZE+" bytes, has "+stream.available()+" bytes"); + } + try { + stream.mark(MAGIC_MAX_SIZE); + final int bytesRead = stream.read(b); + if( MAGIC_MAX_SIZE > bytesRead ) { + throw new IOException("Could not read "+MAGIC_MAX_SIZE+" bytes, read "+bytesRead+" bytes"); + } + return getFileSuffix(b); + } finally { + stream.reset(); + } + + } + + /** + * Determines the file suffix (i.e the image format) of the given bytes from the header + * of a file. + * + * @param b byte array to parse, size must be ≥ {@link #MAGIC_MAX_SIZE} + * @return the file suffix if any, otherwise <code>null</code> + * @throws java.io.IOException if an I/O exception occurred + */ + public static String getFileSuffix(final byte[] b) { + if( b.length < MAGIC_MAX_SIZE ) { + throw new IllegalArgumentException("byte array must be >= "+MAGIC_MAX_SIZE+", has "+b.length); + } + final byte b0 = b[0]; + final byte b1 = b[1]; + final byte b2 = b[2]; + final byte b3 = b[3]; + final byte b4 = b[4]; + final byte b5 = b[5]; + + // T_TGA: NO Signature! + + if (b0 == (byte)0x00) { + if (b1 == (byte)0x00 && b2 == (byte)0x00 && b3 == (byte)0x0C && + b4 == (byte)0x6A && b5 == (byte)0x50 && + b[6] == (byte)0x20 && b[7] == (byte)0x20 && b[8] == (byte)0x0D && b[9] == (byte)0x0A && b[10] == (byte)0x87 && + b[11] == (byte)0x0A) { + return T_JP2; + } + else if (b1 == (byte)0x01) { + return T_ICO; + } + else if (b1 == (byte)0x02) { + return T_CUR; + } + } + else if (b0 == (byte)0x01) { + if (b1 == (byte)0xDA /* && b2 == (byte)0x01 && b3 == (byte)0x01 && b4 == (byte)0x00 && b5 == (byte)0x03 */) { + return T_SGI_RGB; + } + else if (b1 == (byte)0xFF && b2 == (byte)0x02 && b3 == (byte)0x04 && + b4 == (byte)0x03 && b5 == (byte)0x02) { + return T_DRW; + } + else if (b1 == (byte)0x00 && b2 == (byte)0x00 && b3 == (byte)0x00 && + b4 == (byte)0x58 && b5 == (byte)0x00 && + b[6] == (byte)0x00 && b[7] == (byte)0x00) { + return T_EMF; + } + } + else if (b0 == (byte)0x07 && b1 == (byte)0x20 && b2 == (byte)0x4D && b3 == (byte)0x4D) { + return T_CAM; + } + else if (b0 == (byte)0x0A && b1 == (byte)0x05 && b2 == (byte)0x01 && b3 == (byte)0x08) { + return T_PCX; + } + else if (b0 == (byte)0x1B && b1 == (byte)0x45 && b2 == (byte)0x1B && b3 == (byte)0x26 && + b4 == (byte)0x6C && b5 == (byte)0x30 && + b[6] == (byte)0x4F && b[7] == (byte)0x1B && b[8] == (byte)0x26 && b[9] == (byte)0x6C && b[10] == (byte)0x30 && + b[11] == (byte)0x45 && b[12] == (byte)0x1B && b[13] == (byte)0x26) { + return T_PCL; + } + else if (b0 == (byte)0x20 && b1 == (byte)0x77 && b2 == (byte)0x00 && b3 == (byte)0x02) { + return T_CBD; + } + else if (b0 == (byte)0x23) { + if (b1 == (byte)0x20 && b2 == (byte)0x24 && b3 == (byte)0x49 && + b4 == (byte)0x64 && b5 == (byte)0x3A && + b[6] == (byte)0x20) { + return T_SID; + } + else if (b1 == (byte)0x56 && b2 == (byte)0x52 && b3 == (byte)0x4D && + b4 == (byte)0x4C && b5 == (byte)0x20 && + b[6] == (byte)0x56 && b[7] == (byte)0x32 && b[8] == (byte)0x2E && b[9] == (byte)0x30) { + return T_WRL; + } + else if (b1 == (byte)0x64 && b2 == (byte)0x65 && b3 == (byte)0x66 && + b4 == (byte)0x69 && b5 == (byte)0x6E && + b[6] == (byte)0x65) { + return T_XBM; + } + } + else if (b0 == (byte)0x2A && b1 == (byte)0x2A && b2 == (byte)0x54 && b3 == (byte)0x49 && + b4 == (byte)0x39 && b5 == (byte)0x32 && + b[6] == (byte)0x2A && b[7] == (byte)0x2A && b[8] == (byte)0x01 && b[9] == (byte)0x00 && b[10] == (byte)0x58 && + b[11] == (byte)0x6E && b[12] == (byte)0x56 && b[13] == (byte)0x69) { + return T_92I; + } + else if (b0 == (byte)0x2F && b1 == (byte)0x2A && b2 == (byte)0x20 && b3 == (byte)0x58 && + b4 == (byte)0x50 && b5 == (byte)0x4D && + b[6] == (byte)0x20 && b[7] == (byte)0x2A && b[8] == (byte)0x2F) { + return T_XPM; + } + else if (b0 == (byte)0x33 && b1 == (byte)0x44 && b2 == (byte)0x4D && b3 == (byte)0x46) { + return T_3DMF; + } + else if (b0 == (byte)0x35 && b1 == (byte)0x4B && b2 == (byte)0x50 && b3 == (byte)0x35 && + b4 == (byte)0x31 && b5 == (byte)0x5D && + b[6] == (byte)0x2A && b[7] == (byte)0x67 && b[8] == (byte)0x72 && b[9] == (byte)0x72 && b[10] == (byte)0x80 && + b[11] == (byte)0x83 && b[12] == (byte)0x85 && b[13] == (byte)0x63) { + return T_HRU; + } + else if (b0 == (byte)0x36 && b1 == (byte)0x34 && b2 == (byte)0x4C && b3 == (byte)0x41 && + b4 == (byte)0x4E && b5 == (byte)0x20 && + b[6] == (byte)0x49 && b[7] == (byte)0x44 && b[8] == (byte)0x42 && b[9] == (byte)0x4C && b[10] == (byte)0x4F && + b[11] == (byte)0x43 && b[12] == (byte)0x4B) { + return T_L64; + } + else if (b0 == (byte)0x37 && b1 == (byte)0x00 && b2 == (byte)0x00 && b3 == (byte)0x10 && + b4 == (byte)0x42 && b5 == (byte)0x00 && + b[6] == (byte)0x00 && b[7] == (byte)0x10 && b[8] == (byte)0x00 && b[9] == (byte)0x00 && b[10] == (byte)0x00 && + b[11] == (byte)0x00 && b[12] == (byte)0x39 && b[13] == (byte)0x64) { + return T_MBM; + } + else if (b0 == (byte)0x38 && b1 == (byte)0x42 && b2 == (byte)0x50 && b3 == (byte)0x53 && + b4 == (byte)0x00 && b5 == (byte)0x01 && + b[6] == (byte)0x00 && b[7] == (byte)0x00 && b[8] == (byte)0x00 && b[9] == (byte)0x00) { + return T_PSD; + } + else if (b0 == (byte)0x3A && b1 == (byte)0xDE && b2 == (byte)0x68 && b3 == (byte)0xB1) { + return T_DCX; + } + else if (b0 == (byte)0x3D && b1 == (byte)0x02) { + return T_3D2; + } + else if (b0 == (byte)0x41) { + if (b1 == (byte)0x43 && b2 == (byte)0x31 && b3 == (byte)0x30) { + return T_DWG; + } + else if (b1 == (byte)0x48) { + return T_PAL; + } + else if (b1 == (byte)0x4D && b2 == (byte)0x46 && b3 == (byte)0x46) { + return T_AMFF; + } + else if (b1 == (byte)0x75 && b2 == (byte)0x74 && b3 == (byte)0x6F && + b4 == (byte)0x43 && b5 == (byte)0x41 && + b[6] == (byte)0x44 && b[7] == (byte)0x20 && b[8] == (byte)0x53 && b[9] == (byte)0x6C && b[10] == (byte)0x69 && + b[11] == (byte)0x64 && b[12] == (byte)0x65) { + return T_SLD; + } + } + else if (b0 == (byte)0x42 && b1 == (byte)0x4D) { + if (b2 == (byte)0x36) { + // FIXME: Collision or subtype of T_BMP? + return T_DIB; + } else { + return T_BMP; + } + } + else if (b0 == (byte)0x43) { + if (b1 == (byte)0x36 && b2 == (byte)0x34) { + return T_N64; + } + else if (b1 == (byte)0x41 && b2 == (byte)0x4C && b3 == (byte)0x41 && + b4 == (byte)0x4D && b5 == (byte)0x55 && + b[6] == (byte)0x53 && b[7] == (byte)0x43 && b[8] == (byte)0x56 && b[9] == (byte)0x47) { + return T_CVG; + } + else if (b1 == (byte)0x50 && b2 == (byte)0x54 && b3 == (byte)0x46 && + b4 == (byte)0x49 && b5 == (byte)0x4C && + b[6] == (byte)0x45) { + return T_CPT; + } + else if (b1 == (byte)0x61 && b2 == (byte)0x6C && b3 == (byte)0x69 && + b4 == (byte)0x67 && b5 == (byte)0x61 && + b[6] == (byte)0x72 && b[7] == (byte)0x69) { + return T_COB; + } + } + else if (b0 == (byte)0x44) { + if (b1 == (byte)0x44 && b2 == (byte)0x53 && b3 == (byte)0x20) { + return T_DDS; + } + else if (b1 == (byte)0x61 && b2 == (byte)0x6E && b3 == (byte)0x4D) { + return T_MSP; + } + } + else if (b0 == (byte)0x45) { + if (b1 == (byte)0x59 && b2 == (byte)0x45 && b3 == (byte)0x53) { + return T_CE2; + } + else if (b1 == (byte)0x78 && b2 == (byte)0x69 && b3 == (byte)0x66) { /* EXIF */ + /** + * (b0 == (byte)0x45 && b1 == (byte)0x78 && b2 == (byte)0x69 && b3 == (byte)0x66) || // EXIF + * (b0 == (byte)0x4A && b1 == (byte)0x46 && b2 == (byte)0x49 && b3 == (byte)0x46) || // JFIF + * (b0 == (byte)0xff && b1 == (byte)0xd8 ) // && b2 == (byte)0xff + */ + return T_JPG; + } + } + else if (b0 == (byte)0x46 && b1 == (byte)0x4F && b2 == (byte)0x52 && b3 == (byte)0x4D) { + if (b4 == (byte)0x41 && b5 == (byte)0x54 && b[6] == (byte)0x3D) { + // FIXME: Collision or subtype of T_LBM? + return T_RAD; + } else { + return T_LBM; + } + } + else if (b0 == (byte)0x47 && b1 == (byte)0x49 && b2 == (byte)0x46 && b3 == (byte)0x38 && + (b4 == (byte)0x37 || b4 == (byte)0x39) && b5 == (byte)0x61) { + return T_GIF; + } + else if (b0 == (byte)0x48 && b1 == (byte)0x50 && b2 == (byte)0x48 && b3 == (byte)0x50 && + b4 == (byte)0x34 && b5 == (byte)0x38 && + b[6] == (byte)0x2D && b[7] == (byte)0x45 && b[8] == (byte)0x1E && b[9] == (byte)0x2B) { + return T_GRO; + } + else if (b0 == (byte)0x49) { + if (b1 == (byte)0x49 && b2 == (byte)0x2A && b3 == (byte)0x00) { + if (b4 == (byte)0x08 && b5 == (byte)0x00 && + b[6] == (byte)0x00 && b[7] == (byte)0x00 && b[8] == (byte)0x0E && b[9] == (byte)0x00 && b[10] == (byte)0x00 && + b[11] == (byte)0x01 && b[12] == (byte)0x04 && b[13] == (byte)0x00) { + // FIXME: Collision or subtype of T_TIFF? + return T_LDF; + } else { + return T_TIFF; + } + } + else if (b1 == (byte)0x57 && b2 == (byte)0x43 && b3 == (byte)0x01) { + return T_IWC; + } + } + else if (b0 == (byte)0x4A) { + if (b1 == (byte)0x46 && b2 == (byte)0x49 && b3 == (byte)0x46) { /* JFIF */ + /** + * (b0 == (byte)0x45 && b1 == (byte)0x78 && b2 == (byte)0x69 && b3 == (byte)0x66) || // EXIF + * (b0 == (byte)0x4A && b1 == (byte)0x46 && b2 == (byte)0x49 && b3 == (byte)0x46) || // JFIF + * (b0 == (byte)0xff && b1 == (byte)0xd8 ) // && b2 == (byte)0xff + */ + return T_JPG; + } + else if (b1 == (byte)0x47 && (b2 == (byte)0x03 || b2 == (byte)0x04) && b3 == (byte)0x0E && + b4 == (byte)0x00 && b5 == (byte)0x00 && + b[6] == (byte)0x00) { + return T_ART; + } + else if (b1 == (byte)0x49 && b2 == (byte)0x46 && b3 == (byte)0x39 && + b4 == (byte)0x39 && b5 == (byte)0x61) { + return T_JIF; + } + } + else if (b0 == (byte)0x4D) { + if (b1 == (byte)0x47 && b2 == (byte)0x4C) { + return T_MGL; + } + else if (b1 == (byte)0x4D && b2 == (byte)0x00 && b3 == (byte)0x2A) { + return T_KDC; + } + else if (b1 == (byte)0x50 && b2 == (byte)0x46) { + return T_MPW; + } + } + else if (b0 == (byte)0x4E) { + if (b1 == (byte)0x47 && b2 == (byte)0x47 && b3 == (byte)0x00 && + b4 == (byte)0x01 && b5 == (byte)0x00) { + return T_NGG; + } + else if (b1 == (byte)0x4C && b2 == (byte)0x4D && b3 == (byte)0x20 && + b4 == (byte)0x01 && b5 == (byte)0x02 && + b[6] == (byte)0x00) { + return T_NLM; + } + else if (b1 == (byte)0x4F && b2 == (byte)0x4C && b3 == (byte)0x00 && + b4 == (byte)0x01 && b5 == (byte)0x00 && + b[6] == (byte)0x06 && b[7] == (byte)0x01 && b[8] == (byte)0x03 && b[9] == (byte)0x00) { + return T_NOL; + } + } + else if (b0 == (byte)0x50) { + if (b1 == (byte)0x31 /* plain */|| b1 == (byte)0x34) { + return T_PBM; + } + else if (b1 == (byte)0x32 /* plain */|| b1 == (byte)0x35) { + return T_PGM; + } + else if (b1 == (byte)0x33 /* plain */|| b1 == (byte)0x36) { + return T_PPM; + } + else if (b1 == (byte)0x37) { + return T_PAM; + } + else if (b1 == (byte)0x41 && b2 == (byte)0x58) { + return T_PAX; + } + else if (b1 == (byte)0x49 && b2 == (byte)0x58 && b3 == (byte)0x20) { + return T_PIX; + } + else if (b1 == (byte)0x4F && b2 == (byte)0x4C && b3 == (byte)0x20 && + b4 == (byte)0x46 && b5 == (byte)0x6F && + b[6] == (byte)0x72 && b[7] == (byte)0x6D && b[8] == (byte)0x61 && b[9] == (byte)0x74) { + return T_POL; + } + else if (b1 == (byte)0x61 && b2 == (byte)0x69 && b3 == (byte)0x6E && + b4 == (byte)0x74 && b5 == (byte)0x20 && + b[6] == (byte)0x53 && b[7] == (byte)0x68 && b[8] == (byte)0x6F && b[9] == (byte)0x70 && b[10] == (byte)0x20 && + b[11] == (byte)0x50 && b[12] == (byte)0x72 && b[13] == (byte)0x6F && b[14] == (byte)0x20 && b[15] == (byte)0x49 && + b[16] == (byte)0x6D && b[17] == (byte)0x61 && b[18] == (byte)0x67 && b[19] == (byte)0x65 && b[20] == (byte)0x20 && + b[21] == (byte)0x46 && b[22] == (byte)0x69 && b[23] == (byte)0x6C && b[24] == (byte)0x65) { + return T_PSP; + } + } + else if (b0 == (byte)0x51 && b1 == (byte)0x4C && b2 == (byte)0x49 && b3 == (byte)0x49 && + b4 == (byte)0x46 && b5 == (byte)0x41 && + b[6] == (byte)0x58) { + return T_QFX; + } + else if (b0 == (byte)0x52 && b1 == (byte)0x49 && b2 == (byte)0x58 && b3 == (byte)0x33) { + return T_RIX; + } + else if (b0 == (byte)0x53) { + if (b1 == (byte)0x44 && b2 == (byte)0x50 && b3 == (byte)0x58) { + return T_DPX; + } + else if (b1 == (byte)0x49 && b2 == (byte)0x4D && b3 == (byte)0x50 && + b4 == (byte)0x4C && b5 == (byte)0x45 && + b[6] == (byte)0x20 && b[7] == (byte)0x20 && b[8] == (byte)0x3D) { + return T_FTS; + } + else if (b1 == (byte)0x74 && b2 == (byte)0x6F && b3 == (byte)0x72 && + b4 == (byte)0x6D && b5 == (byte)0x33 && + b[6] == (byte)0x44) { + return T_SOD; + } + else if (b1 == (byte)0x80 && b2 == (byte)0xf6 && b3 == (byte)0x34) { + return T_PIC; + } + } + else if (b0 == (byte)0x56 && b1 == (byte)0x69 && b2 == (byte)0x73 && b3 == (byte)0x74 && + b4 == (byte)0x61 && b5 == (byte)0x20 && + b[6] == (byte)0x44 && b[7] == (byte)0x45 && b[8] == (byte)0x4D && b[9] == (byte)0x20 && b[10] == (byte)0x46 && + b[11] == (byte)0x69 && b[12] == (byte)0x6C && b[13] == (byte)0x65) { + return T_DEM; + } + else if (b0 == (byte)0x57 && b1 == (byte)0x56 && b2 == (byte)0x02 && b3 == (byte)0x00 && + b4 == (byte)0x47 && b5 == (byte)0x45 && + b[6] == (byte)0x00 && b[7] == (byte)0x0E) { + return T_LWF; + } + else if (b0 == (byte)0x59 && b1 == (byte)0xA6 && b2 == (byte)0x6A && b3 == (byte)0x95) { + return T_RAS; + } + else if (b0 == (byte)0x63 && b1 == (byte)0x52 && b2 == (byte)0x01 && b3 == (byte)0x01 && + b4 == (byte)0x38 && b5 == (byte)0x09 && + b[6] == (byte)0x3D && b[7] == (byte)0x00) { + return T_PCD; + } + else if (b0 == (byte)0x65) { + if (b1 == (byte)0x02 && b2 == (byte)0x01 && b3 == (byte)0x02) { + return T_ECW; + } + else if (b1 == (byte)0x6C && b2 == (byte)0x6D && b3 == (byte)0x6F) { + return T_INFINI_D; + } + } + else if (b0 == (byte)0x69 && b1 == (byte)0x63 && b2 == (byte)0x6E && b3 == (byte)0x73) { + return T_ICNS; + } + else if (b0 == (byte)0x6D && b1 == (byte)0x6F && b2 == (byte)0x6F && b3 == (byte)0x76) { + return T_QTM; + } + else if (b0 == (byte)0x6E) { + if (b1 == (byte)0x63 && b2 == (byte)0x6F && b3 == (byte)0x6C && + b4 == (byte)0x73) { + return T_HDR; + } + else if (b1 == (byte)0x66 && b2 == (byte)0x66) { + return T_NFF; + } + else if (b1 == (byte)0x6E && b2 == (byte)0x0A && b3 == (byte)0x00 && + b4 == (byte)0x5E && b5 == (byte)0x00) { + return T_NCR; + } + } + else if (b0 == (byte)0x73 && b1 == (byte)0x72 && b2 == (byte)0x63 && b3 == (byte)0x64 && + b4 == (byte)0x6F && b5 == (byte)0x63 && + b[6] == (byte)0x69 && b[7] == (byte)0x64 && b[8] == (byte)0x3A) { + return T_CALS; + } + else if (b0 == (byte)0x7B && b1 == (byte)0x0A && b2 == (byte)0x20 && b3 == (byte)0x20 && + b4 == (byte)0x43 && b5 == (byte)0x72 && + b[6] == (byte)0x65 && b[7] == (byte)0x61 && b[8] == (byte)0x74 && b[9] == (byte)0x65 && b[10] == (byte)0x64) { + return T_MIF; + } + else if (b0 == (byte)0x7E && b1 == (byte)0x42 && b2 == (byte)0x4B && b3 == (byte)0x00) { + return T_PSP; + } + else if (b0 == (byte)0x80) { + if (b1 == (byte)0x2A && b2 == (byte)0x5F && b3 == (byte)0xD7 && + b4 == (byte)0x00 && b5 == (byte)0x00 && + b[6] == (byte)0x08 && b[7] == (byte)0x00 && b[8] == (byte)0x00 && b[9] == (byte)0x00 && b[10] == (byte)0x04 && + b[11] == (byte)0x00 && b[12] == (byte)0x00 && b[13] == (byte)0x00) { + return T_CIN; + } + else if (b1 == (byte)0x3E && b2 == (byte)0x44 && b3 == (byte)0x53 && + b4 == (byte)0x43 && b5 == (byte)0x49 && + b[6] == (byte)0x4D) { + return T_J6I; + } + } + else if (b0 == (byte)0x89 && b1 == (byte)0x50 && b2 == (byte)0x4E && b3 == (byte)0x47 && /* 'P' 'N' 'G', ascii code */ + b4 == (byte)0x0D && b5 == (byte)0x0A && b[6] == (byte)0x1A && b[7] == (byte)0x0A) { + // -119, 80, 78, 71, 13, 10, 26, 10 + return T_PNG; + } + else if (b0 == (byte)0x8A && b1 == (byte)0x4D && b2 == (byte)0x4E && b3 == (byte)0x47 && + b4 == (byte)0x0D && b5 == (byte)0x0A && + b[6] == (byte)0x1A && b[7] == (byte)0x0A) { + return T_MNG; + } + else if (b0 == (byte)0xD0 && b1 == (byte)0xCF && b2 == (byte)0x11 && b3 == (byte)0xE0 && + b4 == (byte)0xA1 && b5 == (byte)0xB1 && + b[6] == (byte)0x1A && b[7] == (byte)0xE1 && b[8] == (byte)0x00) { + return T_FPX; + } + else if (b0 == (byte)0xD3 && b1 == (byte)0x23 && b2 == (byte)0x00 && b3 == (byte)0x00 && + b4 == (byte)0x03 && b5 == (byte)0x00 && + b[6] == (byte)0x00 && b[7] == (byte)0x00) { + return T_WLM; + } + else if (b0 == (byte)0xD7 && b1 == (byte)0xCD && b2 == (byte)0xC6 && b3 == (byte)0x9A) { + return T_WMF; + } + else if (b0 == (byte)0xEB && b1 == (byte)0x3C && b2 == (byte)0x90 && b3 == (byte)0x2A) { + return T_IMG; + } + else if (b0 == (byte)0xFA && b1 == (byte)0xDE && b2 == (byte)0xBA && b3 == (byte)0xBE && + b4 == (byte)0x01 && b5 == (byte)0x01) { + return T_WIC; + } + else if (b0 == (byte)0xFF) { + if (b1 == (byte)0xD8 /* && b2 == (byte)0xff */) { + /** + * (b0 == (byte)0x45 && b1 == (byte)0x78 && b2 == (byte)0x69 && b3 == (byte)0x66) || // EXIF + * (b0 == (byte)0x4A && b1 == (byte)0x46 && b2 == (byte)0x49 && b3 == (byte)0x46) || // JFIF + * (b0 == (byte)0xff && b1 == (byte)0xd8 ) // && b2 == (byte)0xff + */ + return T_JPG; + } + else if (b1 == (byte)0x57 && b2 == (byte)0x50 && b3 == (byte)0x43 && b4 == (byte)0x10) { + return T_WPG; + } + } + return null; + } + } +} 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 18a7527b6..bdaa2d792 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java @@ -163,8 +163,10 @@ import com.jogamp.opengl.util.texture.spi.*; * @author Chris Campbell, Kenneth Russell, et.al. */ public class Texture { - /** The GL target type. */ + /** The GL target type for this texture. */ private int target; + /** The image GL target type for this texture, or its sub-components if cubemap. */ + private int imageTarget; /** The GL texture ID. */ private int texID; /** The width of the texture. */ @@ -190,7 +192,8 @@ public class Texture { @Override public String toString() { - return "Texture[target 0x"+Integer.toHexString(target)+", name "+texID+", "+ + final String targetS = target == imageTarget ? Integer.toHexString(target) : Integer.toHexString(target) + " - image "+Integer.toHexString(imageTarget); + return "Texture[target "+targetS+", name "+texID+", "+ imgWidth+"/"+texWidth+" x "+imgHeight+"/"+texHeight+", y-flip "+mustFlipVertically+ ", "+estimatedMemorySize+" bytes]"; } @@ -206,7 +209,9 @@ public class Texture { private static final boolean disableTexRect = Debug.isPropertyDefined("jogl.texture.notexrect", true); public Texture(final GL gl, final TextureData data) throws GLException { - texID = 0; + this.texID = 0; + this.target = 0; + this.imageTarget = 0; updateImage(gl, data); } @@ -217,8 +222,9 @@ public class Texture { * GL2.GL_TEXTURE_RECTANGLE */ public Texture(final int target) { - texID = 0; + this.texID = 0; this.target = target; + this.imageTarget = target; } /** @@ -250,11 +256,14 @@ public class Texture { final boolean mustFlipVertically) { this.texID = textureID; this.target = target; + this.imageTarget = target; this.mustFlipVertically = mustFlipVertically; this.texWidth = texWidth; this.texHeight = texHeight; - aspectRatio = (float) imgWidth / (float) imgHeight; - setImageSize(imgWidth, imgHeight, target); + this.aspectRatio = (float) imgWidth / (float) imgHeight; + this.imgWidth = imgWidth; + this.imgHeight = imgHeight; + this.updateTexCoords(); } /** @@ -344,8 +353,6 @@ public class Texture { /** * Returns the OpenGL "target" of this texture. - * - * @return the OpenGL target of this texture * @see com.jogamp.opengl.GL#GL_TEXTURE_2D * @see com.jogamp.opengl.GL2#GL_TEXTURE_RECTANGLE_ARB */ @@ -354,6 +361,15 @@ public class Texture { } /** + * Returns the image OpenGL "target" of this texture, or its sub-components if cubemap. + * @see com.jogamp.opengl.GL#GL_TEXTURE_2D + * @see com.jogamp.opengl.GL2#GL_TEXTURE_RECTANGLE_ARB + */ + public int getImageTarget() { + return imageTarget; + } + + /** * Returns the width of the allocated OpenGL texture in pixels. * Note that the texture width will be greater than or equal to the * width of the image contained within. @@ -438,7 +454,7 @@ public class Texture { * @return the texture coordinates corresponding to the specified sub-image */ public TextureCoords getSubImageTexCoords(final int x1, final int y1, final int x2, final int y2) { - if (target == GL2.GL_TEXTURE_RECTANGLE_ARB) { + if (GL2.GL_TEXTURE_RECTANGLE_ARB == imageTarget) { if (mustFlipVertically) { return new TextureCoords(x1, texHeight - y1, x2, texHeight - y2); } else { @@ -616,17 +632,17 @@ public class Texture { texHeight = nextPowerOfTwo(imgHeight); texTarget = GL.GL_TEXTURE_2D; } - texParamTarget = texTarget; - setImageSize(imgWidth, imgHeight, texTarget); + imageTarget = texTarget; + updateTexCoords(); if (targetOverride != 0) { // Allow user to override auto detection and skip bind step (for // cubemap construction) - texTarget = targetOverride; if (this.target == 0) { throw new GLException("Override of target failed; no target specified yet"); } + texTarget = targetOverride; texParamTarget = this.target; gl.glBindTexture(texParamTarget, texID); } else { @@ -977,17 +993,8 @@ public class Texture { return ret; } - /** - * Updates the actual image dimensions; usually only called from - * <code>updateImage</code>. - */ - private void setImageSize(final int width, final int height, final int target) { - imgWidth = width; - imgHeight = height; - updateTexCoords(); - } private void updateTexCoords() { - if (target == GL2.GL_TEXTURE_RECTANGLE_ARB) { + if ( GL2.GL_TEXTURE_RECTANGLE_ARB == imageTarget ) { if (mustFlipVertically) { coords = new TextureCoords(0, imgHeight, imgWidth, 0); } else { diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java index 615d8c24f..5799f95a6 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java @@ -83,6 +83,9 @@ public class TextureData { protected GLProfile glProfile; protected ColorSpace pixelCS = ColorSpace.RGB; + // TODO: final, and set via ctor for 2.4.X + /* pp */ ImageType srcImageType; + /** * Constructs a new TextureData object with the specified parameters * and data contained in the given Buffer. The optional Flusher can @@ -341,6 +344,14 @@ public class TextureData { /** Used only by subclasses */ protected TextureData(final GLProfile glp) { this.glProfile = glp; this.pixelAttributes = GLPixelAttributes.UNDEF; } + /** + * Returns the source {@link ImageType} if applicable and known, otherwise {@code null}. + * @since 2.3.2 + */ + public final ImageType getSourceImageType() { + return srcImageType; + } + /** Returns the width in pixels of the texture data. */ public int getWidth() { return width; } /** Returns the height in pixels of the texture data. */ @@ -501,8 +512,9 @@ public class TextureData { @Override public String toString() { + final String optImageType = null != srcImageType ? ", "+srcImageType : ""; return "TextureData["+width+"x"+height+", y-flip "+mustFlipVertically+", internFormat 0x"+Integer.toHexString(internalFormat)+", "+ - pixelAttributes+", border "+border+", estSize "+estimatedMemorySize+", alignment "+alignment+", rowlen "+rowLength; + pixelAttributes+", border "+border+", estSize "+estimatedMemorySize+", alignment "+alignment+", rowlen "+rowLength+optImageType; } //---------------------------------------------------------------------- diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java index 80b195642..2ac7c796d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java @@ -52,8 +52,10 @@ import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import com.jogamp.nativewindow.util.Dimension; import com.jogamp.nativewindow.util.DimensionImmutable; @@ -72,6 +74,7 @@ import com.jogamp.common.util.IOUtil; import com.jogamp.opengl.util.GLPixelStorageModes; import com.jogamp.opengl.util.PNGPixelRect; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; +import com.jogamp.opengl.util.texture.ImageType; import com.jogamp.opengl.util.texture.spi.DDSImage; import com.jogamp.opengl.util.texture.spi.JPEGImage; import com.jogamp.opengl.util.texture.spi.NetPbmTextureWriter; @@ -134,44 +137,60 @@ import com.jogamp.opengl.util.texture.spi.TextureWriter; public class TextureIO { /** Constant which can be used as a file suffix to indicate a - DirectDraw Surface file. */ - public static final String DDS = "dds"; + DirectDraw Surface file, value {@value}. + <p>Alias for {@link ImageType#T_DDS}.</p> + */ + public static final String DDS = ImageType.T_DDS; - /** Constant which can be used as a file suffix to indicate an SGI - RGB file. */ + /** + * Constant which can be used as a file suffix to indicate an SGI RGB file, value {@value}. + * <p> + * Same semantics as {@link ImageType#SGI_RGB} and {@link #SGI_RGB}. + * </p> + */ public static final String SGI = "sgi"; - /** Constant which can be used as a file suffix to indicate an SGI - RGB file. */ - public static final String SGI_RGB = "rgb"; + /** Constant which can be used as a file suffix to indicate an SGI RGB file, value {@value}. + <p>Alias for {@link ImageType#T_SGI_RGB}. </p> + */ + public static final String SGI_RGB = ImageType.T_SGI_RGB; - /** Constant which can be used as a file suffix to indicate a GIF - file. */ - public static final String GIF = "gif"; + /** Constant which can be used as a file suffix to indicate a GIF file, value {@value}. + <p>Alias for {@link ImageType#T_GIF}.</p> + */ + public static final String GIF = ImageType.T_GIF; - /** Constant which can be used as a file suffix to indicate a JPEG - file. */ - public static final String JPG = "jpg"; + /** Constant which can be used as a file suffix to indicate a JPEG file, value {@value}. + <p>Alias for {@link ImageType#T_JPG}.</p> + */ + public static final String JPG = ImageType.T_JPG; - /** Constant which can be used as a file suffix to indicate a PNG - file. */ - public static final String PNG = "png"; + /** Constant which can be used as a file suffix to indicate a PNG file, value {@value}. + <p>Alias for {@link ImageType#T_PNG}.</p> + */ + public static final String PNG = ImageType.T_PNG; - /** Constant which can be used as a file suffix to indicate a Targa - file. */ - public static final String TGA = "tga"; + /** Constant which can be used as a file suffix to indicate a Targa file, value {@value}. + <p>Alias for {@link ImageType#T_TGA}.</p> + */ + public static final String TGA = ImageType.T_TGA; - /** Constant which can be used as a file suffix to indicate a TIFF - file. */ - public static final String TIFF = "tiff"; + /** Constant which can be used as a file suffix to indicate a TIFF file, value {@value}. + <p>Alias for {@link ImageType#T_TIFF}.</p> + */ + public static final String TIFF = ImageType.T_TIFF; /** Constant which can be used as a file suffix to indicate a PAM - file, NetPbm magic 7 - binary RGB and RGBA. Write support only. */ - public static final String PAM = "pam"; + file, NetPbm magic 7 - binary RGB and RGBA. Write support only, value {@value}. + <p>Alias for {@link ImageType#T_PAM}.</p> + */ + public static final String PAM = ImageType.T_PAM; /** Constant which can be used as a file suffix to indicate a PAM - file, NetPbm magic 6 - binary RGB. Write support only. */ - public static final String PPM = "ppm"; + file, NetPbm magic 6 - binary RGB. Write support only, value {@value}. + <p>Alias for {@link ImageType#T_PPM}.</p> + */ + public static final String PPM = ImageType.T_PPM; private static final boolean DEBUG = Debug.debug("TextureIO"); @@ -677,16 +696,27 @@ public class TextureIO { // /** - * Adds a TextureProvider to support reading of a new file format. + * Adds a {@link TextureProvider} to support reading of a new file format. * <p> * The last provider added, will be the first provider to be tested. * </p> + * <p> + * The {@link TextureProvider} is being mapped to its supporting {@link ImageType}s + * allowing an O(1) association, if {@link TextureProvider#} + * </p> */ public static void addTextureProvider(final TextureProvider provider) { // Must always add at the front so the ImageIO provider is last, // so we don't accidentally use it instead of a user's possibly // more optimal provider textureProviders.add(0, provider); + + final ImageType[] imageTypes = provider.getImageTypes(); + if( null != imageTypes ) { + for(int i=0; i<imageTypes.length; i++) { + imageType2TextureProvider.put(imageTypes[i], provider); + } + } } /** @@ -736,6 +766,7 @@ public class TextureIO { // private static List<TextureProvider> textureProviders = new ArrayList<TextureProvider>(); + private static Map<ImageType,TextureProvider> imageType2TextureProvider = new HashMap<ImageType,TextureProvider>(); private static List<TextureWriter> textureWriters = new ArrayList<TextureWriter>(); static { @@ -787,32 +818,6 @@ public class TextureIO { } // Implementation methods - private static TextureData newTextureDataImpl(final GLProfile glp, final File file, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - String fileSuffix) throws IOException { - if (file == null) { - throw new IOException("File was null"); - } - - fileSuffix = toLowerCase(fileSuffix); - - for (final Iterator<TextureProvider> iter = textureProviders.iterator(); iter.hasNext(); ) { - final TextureProvider provider = iter.next(); - final TextureData data = provider.newTextureData(glp, file, - internalFormat, - pixelFormat, - mipmap, - fileSuffix); - if (data != null) { - return data; - } - } - - throw new IOException("No suitable reader for given file "+file.getAbsolutePath()); - } - private static TextureData newTextureDataImpl(final GLProfile glp, InputStream stream, final int internalFormat, final int pixelFormat, @@ -822,70 +827,97 @@ public class TextureIO { throw new IOException("Stream was null"); } - fileSuffix = toLowerCase(fileSuffix); - // Note: use of BufferedInputStream works around 4764639/4892246 if (!(stream instanceof BufferedInputStream)) { stream = new BufferedInputStream(stream); } + // First attempt to use an ImageType mapped TextureProvider for O(1) + // using stream parsed data, ignoring the given fileSuffix! + try { + final ImageType imageType = new ImageType(stream); + if( imageType.isDefined() ) { + final TextureProvider mappedProvider = imageType2TextureProvider.get(imageType); + if( null != mappedProvider ) { + final TextureData data = mappedProvider.newTextureData(glp, stream, + internalFormat, + pixelFormat, + mipmap, + imageType.type); + if (data != null) { + data.srcImageType = imageType; + return data; + } + } + } + } catch (final IOException ioe) { + if(DEBUG) { + System.err.println("Caught "+ioe.getMessage()); + ioe.printStackTrace(); + } + } + + fileSuffix = toLowerCase(fileSuffix); + for (final Iterator<TextureProvider> iter = textureProviders.iterator(); iter.hasNext(); ) { final TextureProvider provider = iter.next(); final TextureData data = provider.newTextureData(glp, stream, - internalFormat, - pixelFormat, - mipmap, - fileSuffix); + internalFormat, + pixelFormat, + mipmap, + fileSuffix); if (data != null) { + final ImageType[] imageTypes = provider.getImageTypes(); + data.srcImageType = null != imageTypes ? imageTypes[0] : null; return data; } } throw new IOException("No suitable reader for given stream"); } - + private static TextureData newTextureDataImpl(final GLProfile glp, final File file, + final int internalFormat, + final int pixelFormat, + final boolean mipmap, + final String fileSuffix) throws IOException { + if (file == null) { + throw new IOException("File was null"); + } + final InputStream stream = new BufferedInputStream(new FileInputStream(file)); + try { + return newTextureDataImpl( glp, stream, internalFormat, pixelFormat, mipmap, + (fileSuffix != null) ? fileSuffix : IOUtil.getFileSuffix(file) ); + } catch(final IOException ioe) { + throw new IOException(ioe.getMessage()+", given file "+file.getAbsolutePath(), ioe); + } finally { + stream.close(); + } + } private static TextureData newTextureDataImpl(final GLProfile glp, final URL url, final int internalFormat, final int pixelFormat, final boolean mipmap, - String fileSuffix) throws IOException { + final String fileSuffix) throws IOException { if (url == null) { throw new IOException("URL was null"); } - - fileSuffix = toLowerCase(fileSuffix); - - for (final Iterator<TextureProvider> iter = textureProviders.iterator(); iter.hasNext(); ) { - final TextureProvider provider = iter.next(); - final TextureData data = provider.newTextureData(glp, url, - internalFormat, - pixelFormat, - mipmap, - fileSuffix); - if (data != null) { - return data; - } + final InputStream stream = new BufferedInputStream(url.openStream()); + try { + return newTextureDataImpl(glp, stream, internalFormat, pixelFormat, mipmap, fileSuffix); + } catch(final IOException ioe) { + throw new IOException(ioe.getMessage()+", given URL "+url, ioe); + } finally { + stream.close(); } - - throw new IOException("No suitable reader for given URL "+url); } //---------------------------------------------------------------------- - // DDS provider -- supports files only for now + // DDS image provider static class DDSTextureProvider implements TextureProvider { + private static final ImageType[] imageTypes = new ImageType[] { new ImageType(ImageType.T_DDS) }; @Override - public TextureData newTextureData(final GLProfile glp, final File file, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - final String fileSuffix) throws IOException { - if (DDS.equals(fileSuffix) || - DDS.equals(IOUtil.getFileSuffix(file))) { - final DDSImage image = DDSImage.read(file); - return newTextureData(glp, image, internalFormat, pixelFormat, mipmap); - } - - return null; + public final ImageType[] getImageTypes() { + return imageTypes; } @Override @@ -894,8 +926,8 @@ public class TextureIO { final int pixelFormat, final boolean mipmap, final String fileSuffix) throws IOException { - if (DDS.equals(fileSuffix) || - DDS.equals(ImageIOUtil.getFileSuffix(stream))) { + if (ImageType.T_DDS.equals(fileSuffix) || + ImageType.T_DDS.equals(ImageType.Util.getFileSuffix(stream))) { final byte[] data = IOUtil.copyStream2ByteArray(stream); final ByteBuffer buf = ByteBuffer.wrap(data); final DDSImage image = DDSImage.read(buf); @@ -905,20 +937,6 @@ public class TextureIO { return null; } - @Override - public TextureData newTextureData(final GLProfile glp, final URL url, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - final String fileSuffix) throws IOException { - final InputStream stream = new BufferedInputStream(url.openStream()); - try { - return newTextureData(glp, stream, internalFormat, pixelFormat, mipmap, fileSuffix); - } finally { - stream.close(); - } - } - private TextureData newTextureData(final GLProfile glp, final DDSImage image, int internalFormat, int pixelFormat, @@ -1003,47 +1021,14 @@ public class TextureIO { } //---------------------------------------------------------------------- - // Base class for SGI RGB and TGA image providers - static abstract class StreamBasedTextureProvider implements TextureProvider { - @Override - public TextureData newTextureData(final GLProfile glp, final File file, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - final String fileSuffix) throws IOException { - final InputStream inStream = new BufferedInputStream(new FileInputStream(file)); - try { - // The SGIImage and TGAImage implementations use InputStreams - // anyway so there isn't much point in having a separate code - // path for files - return newTextureData(glp, inStream, - internalFormat, - pixelFormat, - mipmap, - ((fileSuffix != null) ? fileSuffix : IOUtil.getFileSuffix(file))); - } finally { - inStream.close(); - } - } - + // SGI RGB image provider + static class SGITextureProvider implements TextureProvider { + private static final ImageType[] imageTypes = new ImageType[] { new ImageType(ImageType.T_SGI_RGB) }; @Override - public TextureData newTextureData(final GLProfile glp, final URL url, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - final String fileSuffix) throws IOException { - final InputStream stream = new BufferedInputStream(url.openStream()); - try { - return newTextureData(glp, stream, internalFormat, pixelFormat, mipmap, fileSuffix); - } finally { - stream.close(); - } + public final ImageType[] getImageTypes() { + return imageTypes; } - } - //---------------------------------------------------------------------- - // SGI RGB image provider - static class SGITextureProvider extends StreamBasedTextureProvider { @Override public TextureData newTextureData(final GLProfile glp, final InputStream stream, int internalFormat, @@ -1051,9 +1036,9 @@ public class TextureIO { final boolean mipmap, final String fileSuffix) throws IOException { if (SGI.equals(fileSuffix) || - SGI_RGB.equals(fileSuffix) || - SGI.equals(ImageIOUtil.getFileSuffix(stream)) || - SGI_RGB.equals(ImageIOUtil.getFileSuffix(stream))) { + ImageType.T_SGI_RGB.equals(fileSuffix) || + SGI.equals(ImageType.Util.getFileSuffix(stream)) || + ImageType.T_SGI_RGB.equals(ImageType.Util.getFileSuffix(stream))) { final SGIImage image = SGIImage.read(stream); if (pixelFormat == 0) { pixelFormat = image.getFormat(); @@ -1080,14 +1065,20 @@ public class TextureIO { //---------------------------------------------------------------------- // TGA (Targa) image provider - static class TGATextureProvider extends StreamBasedTextureProvider { + static class TGATextureProvider implements TextureProvider { + private static final ImageType[] imageTypes = new ImageType[] { new ImageType(ImageType.T_TGA) }; + @Override + public final ImageType[] getImageTypes() { + return imageTypes; + } + @Override public TextureData newTextureData(final GLProfile glp, final InputStream stream, int internalFormat, int pixelFormat, final boolean mipmap, final String fileSuffix) throws IOException { - if (TGA.equals(fileSuffix)) { + if (ImageType.T_TGA.equals(fileSuffix)) { final TGAImage image = TGAImage.read(glp, stream); if (pixelFormat == 0) { pixelFormat = image.getGLFormat(); @@ -1118,15 +1109,21 @@ public class TextureIO { //---------------------------------------------------------------------- // PNG image provider - static class PNGTextureProvider extends StreamBasedTextureProvider { + static class PNGTextureProvider implements TextureProvider { + private static final ImageType[] imageTypes = new ImageType[] { new ImageType(ImageType.T_PNG) }; + @Override + public final ImageType[] getImageTypes() { + return imageTypes; + } + @Override public TextureData newTextureData(final GLProfile glp, final InputStream stream, int internalFormat, int pixelFormat, final boolean mipmap, final String fileSuffix) throws IOException { - if (PNG.equals(fileSuffix) || - PNG.equals(ImageIOUtil.getFileSuffix(stream))) { + if (ImageType.T_PNG.equals(fileSuffix) || + ImageType.T_PNG.equals(ImageType.Util.getFileSuffix(stream))) { final PNGPixelRect image = PNGPixelRect.read(stream, null, true /* directBuffer */, 0 /* destMinStrideInBytes */, true /* destIsGLOriented */); final GLPixelAttributes glpa = new GLPixelAttributes(glp, image.getPixelformat(), false /* pack */); if ( 0 == pixelFormat ) { @@ -1159,15 +1156,21 @@ public class TextureIO { //---------------------------------------------------------------------- // JPEG image provider - static class JPGTextureProvider extends StreamBasedTextureProvider { + static class JPGTextureProvider implements TextureProvider { + private static final ImageType[] imageTypes = new ImageType[] { new ImageType(ImageType.T_JPG) }; + @Override + public final ImageType[] getImageTypes() { + return imageTypes; + } + @Override public TextureData newTextureData(final GLProfile glp, final InputStream stream, int internalFormat, int pixelFormat, final boolean mipmap, final String fileSuffix) throws IOException { - if (JPG.equals(fileSuffix) || - JPG.equals(ImageIOUtil.getFileSuffix(stream))) { + if (ImageType.T_JPG.equals(fileSuffix) || + ImageType.T_JPG.equals(ImageType.Util.getFileSuffix(stream))) { final JPEGImage image = JPEGImage.read(/*glp, */ stream); if (pixelFormat == 0) { pixelFormat = image.getGLFormat(); @@ -1203,7 +1206,7 @@ public class TextureIO { @Override public boolean write(final File file, final TextureData data) throws IOException { - if (DDS.equals(IOUtil.getFileSuffix(file))) { + if (ImageType.T_DDS.equals(IOUtil.getFileSuffix(file))) { // See whether the DDS writer can handle this TextureData final GLPixelAttributes pixelAttribs = data.getPixelAttributes(); final int pixelFormat = pixelAttribs.format; @@ -1256,7 +1259,7 @@ public class TextureIO { final TextureData data) throws IOException { final String fileSuffix = IOUtil.getFileSuffix(file); if (SGI.equals(fileSuffix) || - SGI_RGB.equals(fileSuffix)) { + ImageType.T_SGI_RGB.equals(fileSuffix)) { // See whether the SGI writer can handle this TextureData final GLPixelAttributes pixelAttribs = data.getPixelAttributes(); final int pixelFormat = pixelAttribs.format; @@ -1300,7 +1303,7 @@ public class TextureIO { @Override public boolean write(final File file, final TextureData data) throws IOException { - if (TGA.equals(IOUtil.getFileSuffix(file))) { + if (ImageType.T_TGA.equals(IOUtil.getFileSuffix(file))) { // See whether the TGA writer can handle this TextureData final GLPixelAttributes pixelAttribs = data.getPixelAttributes(); final int pixelFormat = pixelAttribs.format; @@ -1350,7 +1353,7 @@ public class TextureIO { static class PNGTextureWriter implements TextureWriter { @Override public boolean write(final File file, final TextureData data) throws IOException { - if (PNG.equals(IOUtil.getFileSuffix(file))) { + if (ImageType.T_PNG.equals(IOUtil.getFileSuffix(file))) { // See whether the PNG writer can handle this TextureData final GLPixelAttributes pixelAttribs = data.getPixelAttributes(); final int pixelFormat = pixelAttribs.format; diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/DDSImage.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/DDSImage.java index 36c44a409..246676aae 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/DDSImage.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/DDSImage.java @@ -53,8 +53,7 @@ import java.nio.channels.FileChannel; import com.jogamp.opengl.GL; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IOUtil; -import com.jogamp.opengl.util.GLBuffers; -import com.jogamp.opengl.util.texture.ImageIOUtil; +import com.jogamp.opengl.util.texture.ImageType; /** A reader and writer for DirectDraw Surface (.dds) files, which are used to describe textures. These files can contain multiple mipmap @@ -238,38 +237,6 @@ public class DDSImage { return image; } - /** Determines from the magic number whether the given InputStream - points to a DDS image. The given InputStream must return true - from markSupported() and support a minimum of four bytes of - read-ahead. - - @param in Stream to check - @return true if input stream is DDS image or false otherwise - @throws java.io.IOException if an I/O exception occurred - @deprecated rather call {@link ImageIOUtil#getFileSuffix(InputStream)} - */ - @Deprecated - public static boolean isDDSImage(InputStream in) throws IOException { - if (!(in instanceof BufferedInputStream)) { - in = new BufferedInputStream(in); - } - if (!in.markSupported()) { - throw new IOException("Can not test non-destructively whether given InputStream is a DDS image"); - } - in.mark(4); - int magic = 0; - for (int i = 0; i < 4; i++) { - final int tmp = in.read(); - if (tmp < 0) { - in.reset(); - return false; - } - magic = ((magic >>> 8) | (tmp << 24)); - } - in.reset(); - return (magic == MAGIC); - } - /** * Writes this DDSImage to the specified file name. * @param filename File name to write to diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java index ff8167bb0..47e40e367 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java @@ -42,7 +42,7 @@ package com.jogamp.opengl.util.texture.spi; import java.io.*; import com.jogamp.opengl.*; -import com.jogamp.opengl.util.texture.ImageIOUtil; +import com.jogamp.opengl.util.texture.ImageType; import com.jogamp.common.util.IOUtil; /** <p> Reads and writes SGI RGB/RGBA images. </p> @@ -191,28 +191,6 @@ public class SGIImage { return image; } - /** - * Determines from the magic number whether the given InputStream points to - * an SGI RGB image. The given InputStream must return true from - * markSupported() and support a minimum of two bytes of read-ahead. - * - * @deprecated rather call {@link ImageIOUtil#getFileSuffix(InputStream)} - */ - @Deprecated - public static boolean isSGIImage(InputStream in) throws IOException { - if (!(in instanceof BufferedInputStream)) { - in = new BufferedInputStream(in); - } - if (!in.markSupported()) { - throw new IOException("Can not test non-destructively whether given InputStream is an SGI RGB image"); - } - final DataInputStream dIn = new DataInputStream(in); - dIn.mark(4); - final short magic = dIn.readShort(); - dIn.reset(); - return (magic == MAGIC); - } - /** Returns the width of the image. */ public int getWidth() { return header.xsize; diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/TextureProvider.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/TextureProvider.java index e84f300e2..485a1b82d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/TextureProvider.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/TextureProvider.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2015 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 @@ -39,11 +40,13 @@ package com.jogamp.opengl.util.texture.spi; -import java.io.*; -import java.net.*; +import java.io.IOException; +import java.io.InputStream; + import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.util.texture.ImageType; +import com.jogamp.opengl.util.texture.TextureData; -import com.jogamp.opengl.util.texture.*; /** Plug-in interface to TextureIO to support reading OpenGL textures from new file formats. For all methods, either internalFormat or @@ -54,43 +57,24 @@ import com.jogamp.opengl.util.texture.*; public interface TextureProvider { /** - * Produces a TextureData object from a file, or returns null if the - * file format was not supported by this TextureProvider. Does not - * do any OpenGL-related work. The resulting TextureData can be - * converted into an OpenGL texture in a later step. - * - * @param glp the OpenGL Profile this texture data should be - * created for. - * @param file the file from which to read the texture data - * - * @param internalFormat the OpenGL internal format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param pixelFormat the OpenGL pixel format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param mipmap whether mipmaps should be produced for this - * texture either by autogenerating them or - * reading them from the file. Some file formats - * support multiple mipmaps in a single file in - * which case those mipmaps will be used rather - * than generating them. - * - * @param fileSuffix the file suffix to be used as a hint to the - * provider to more quickly decide whether it - * can handle the file, or null if the - * provider should infer the type from the - * file's contents - * - * @throws IOException if an error occurred while reading the file + * Optional additional interface for {@link TextureProvider} implementation + * exposing the supported {@link ImageType}s. + * <p> + * Use case: Mapping of {@link ImageType}s to {@link TextureProvider}. + * </p> */ - public TextureData newTextureData(GLProfile glp, File file, - int internalFormat, - int pixelFormat, - boolean mipmap, - String fileSuffix) throws IOException; + public static interface SupportsImageTypes { + /** Returns the supported {@link ImageType}s. */ + ImageType[] getImageTypes(); + } + + /** + * Returns the known supported {@link ImageType}s, or {@code null} if unknown. + * <p> + * Use case: Mapping of {@link ImageType}s to {@link TextureProvider}. + * </p> + */ + ImageType[] getImageTypes(); /** * Produces a TextureData object from a stream, or returns null if @@ -130,43 +114,4 @@ public interface TextureProvider { int pixelFormat, boolean mipmap, String fileSuffix) throws IOException; - - /** - * Produces a TextureData object from a URL, or returns null if the - * file format was not supported by this TextureProvider. Does not - * do any OpenGL-related work. The resulting TextureData can be - * converted into an OpenGL texture in a later step. - * - * @param glp the OpenGL Profile this texture data should be - * created for. - * @param url the URL from which to read the texture data - * - * @param internalFormat the OpenGL internal format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param pixelFormat the OpenGL pixel format to be used for - * the texture, or 0 if it should be inferred - * from the file's contents - * - * @param mipmap whether mipmaps should be produced for this - * texture either by autogenerating them or - * reading them from the file. Some file formats - * support multiple mipmaps in a single file in - * which case those mipmaps will be used rather - * than generating them. - * - * @param fileSuffix the file suffix to be used as a hint to the - * provider to more quickly decide whether it - * can handle the file, or null if the - * provider should infer the type from the - * file's contents - * - * @throws IOException if an error occurred while reading the URL - */ - public TextureData newTextureData(GLProfile glp, URL url, - int internalFormat, - int pixelFormat, - boolean mipmap, - String fileSuffix) throws IOException; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/awt/IIOTextureProvider.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/awt/IIOTextureProvider.java index ba762baf3..8ee54899c 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/awt/IIOTextureProvider.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/awt/IIOTextureProvider.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2015 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 @@ -36,39 +37,29 @@ * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ - +// package com.jogamp.opengl.util.texture.spi.awt; -import java.awt.Graphics; -import java.awt.image.*; -import java.io.*; -import java.net.*; -import javax.imageio.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; + +import javax.imageio.ImageIO; + import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.util.texture.ImageType; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.awt.AWTTextureData; +import com.jogamp.opengl.util.texture.spi.TextureProvider; import jogamp.opengl.Debug; -import com.jogamp.opengl.util.texture.*; -import com.jogamp.opengl.util.texture.awt.*; -import com.jogamp.opengl.util.texture.spi.*; public class IIOTextureProvider implements TextureProvider { private static final boolean DEBUG = Debug.debug("TextureIO"); @Override - public TextureData newTextureData(final GLProfile glp, final File file, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - final String fileSuffix) throws IOException { - final BufferedImage img = ImageIO.read(file); - if (img == null) { - return null; - } - if (DEBUG) { - System.out.println("TextureIO.newTextureData(): BufferedImage type for " + file + " = " + - img.getType()); - } - return new AWTTextureData(glp, internalFormat, pixelFormat, mipmap, img); + public final ImageType[] getImageTypes() { + return null; } @Override @@ -87,18 +78,4 @@ public class IIOTextureProvider implements TextureProvider { } return new AWTTextureData(glp, internalFormat, pixelFormat, mipmap, img); } - - @Override - public TextureData newTextureData(final GLProfile glp, final URL url, - final int internalFormat, - final int pixelFormat, - final boolean mipmap, - final String fileSuffix) throws IOException { - final InputStream stream = url.openStream(); - try { - return newTextureData(glp, stream, internalFormat, pixelFormat, mipmap, fileSuffix); - } finally { - stream.close(); - } - } } diff --git a/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java b/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java index e4b0cb2a8..f52292769 100644 --- a/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java +++ b/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java @@ -52,7 +52,6 @@ public class UbuntuFontLoader implements FontSet { private static final Uri.Encoded jarSubDir = Uri.Encoded.cast("atomic/"); private static final Uri.Encoded jarName = Uri.Encoded.cast("jogl-fonts-p0.jar"); - private static final String relFontPath = "fonts/ubuntu/" ; private static final String absFontPath = "jogamp/graph/font/fonts/ubuntu/" ; private static final FontSet fontLoader = new UbuntuFontLoader(); @@ -160,15 +159,14 @@ public class UbuntuFontLoader implements FontSet { } } } - final String path = useTempJARCache ? absFontPath : relFontPath; try { - final Font f = abspathImpl(path+fname, family, style); + final Font f = abspathImpl(absFontPath+fname, family, style); if( null != f ) { return f; } - throw new IOException(String.format("Problem loading font %s, stream %s%s", fname, path, fname)); + throw new IOException(String.format("Problem loading font %s, stream %s%s", fname, absFontPath, fname)); } catch(final Exception e) { - throw new IOException(String.format("Problem loading font %s, stream %s%s", fname, path, fname), e); + throw new IOException(String.format("Problem loading font %s, stream %s%s", fname, absFontPath, fname), e); } } private Font abspathImpl(final String fname, final int family, final int style) throws IOException { @@ -190,7 +188,7 @@ public class UbuntuFontLoader implements FontSet { throw new IOException(privErr[0]); } } else { - final URLConnection urlConn = IOUtil.getResource(UbuntuFontLoader.class, fname); + final URLConnection urlConn = IOUtil.getResource(fname, getClass().getClassLoader(), null); stream = null != urlConn ? urlConn.getInputStream() : null; } if(null != stream) { diff --git a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java index 6025b45ff..5eb429774 100644 --- a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java +++ b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java @@ -48,7 +48,7 @@ public class DesktopGLDynamicLookupHelper extends GLDynamicLookupHelper { gluLibNames.add("libGLU.so"); // unix gluLibNames.add("GLU32"); // windows gluLibNames.add("GLU"); // generic - gluLib = loadFirstAvailable(gluLibNames, null, true); + gluLib = loadFirstAvailable(gluLibNames, true, true, null, true); if(null != gluLib) { nativeLibraries.add(gluLib); } diff --git a/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java b/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java index 331414869..b28b79418 100644 --- a/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java +++ b/src/jogl/classes/jogamp/opengl/ExtensionAvailabilityCache.java @@ -45,7 +45,6 @@ import java.util.StringTokenizer; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES3; -import com.jogamp.opengl.GL2GL3; import com.jogamp.opengl.GLContext; import com.jogamp.common.util.VersionNumber; @@ -138,9 +137,9 @@ final class ExtensionAvailabilityCache { boolean useGetStringi = false; - // Use 'glGetStringi' only for ARB GL3 context, + // Use 'glGetStringi' only for ARB GL3 and ES3 context, // on GL2 platforms the function might be available, but not working. - if ( context.isGL3() ) { + if ( context.isGL3() || context.isGLES3() ) { if ( ! context.isFunctionAvailable("glGetStringi") ) { if(DEBUG) { System.err.println("GLContext: GL >= 3.1 usage, but no glGetStringi"); @@ -156,16 +155,16 @@ final class ExtensionAvailabilityCache { } if(useGetStringi) { - final GL2GL3 gl2gl3 = gl.getGL2GL3(); + final GL2ES3 gl2es3 = (GL2ES3)gl; // validated via context - OK! final int count; { final int[] val = { 0 } ; - gl2gl3.glGetIntegerv(GL2ES3.GL_NUM_EXTENSIONS, val, 0); + gl2es3.glGetIntegerv(GL2ES3.GL_NUM_EXTENSIONS, val, 0); count = val[0]; } final StringBuilder sb = new StringBuilder(); for (int i = 0; i < count; i++) { - final String ext = gl2gl3.glGetStringi(GL.GL_EXTENSIONS, i); + final String ext = gl2es3.glGetStringi(GL.GL_EXTENSIONS, i); if( null == availableExtensionCache.put(ext, ext) ) { // new one if( 0 < i ) { diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index 19fd6c7e1..9d1490300 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -51,6 +51,7 @@ import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.GLSharedContextSetter; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.RunnableTask; import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.opengl.GLAutoDrawableDelegate; import com.jogamp.opengl.GLEventListenerState; @@ -598,6 +599,44 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, GLStateKeepe return helper.getExclusiveContextThread(); } + /** + * Invokes given {@code runnable} on current thread outside of a probable claimed exclusive thread, + * i.e. releases the exclusive thread, executes the runnable and reclaims it. + * FIXME: Promote to GLAutoDrawable! + * + * @param runnable the {@link Runnable} to execute on the new thread. + * The runnable <b>must exit</b>, i.e. not loop forever. + * + * @see #setExclusiveContextThread(Thread, GLContext) + * + * @since 2.3.2 + */ + public final void invokeOnCurrentThread(final Runnable runnable) { + helper.runOutsideOfExclusiveContextThread(context, runnable); + } + /** + * Invokes given {@code runnable} on current thread outside of a probable claimed exclusive thread, + * i.e. releases the exclusive thread, executes the runnable and reclaims it. + * FIXME: Promote to GLAutoDrawable! + * + * @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code> + * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately. + * @param runnable the {@link Runnable} to execute on the new thread. + * The runnable <b>must exit</b>, i.e. not loop forever. + * @return {@link RunnableTask} instance with execution details + * + * @see #setExclusiveContextThread(Thread, GLContext) + * + * @since 2.3.2 + */ + public final RunnableTask invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable) { + return RunnableTask.invokeOnNewThread(tg, null, waitUntilDone, + new Runnable() { + public final void run() { + helper.runOutsideOfExclusiveContextThread(context, runnable); + } }); + } + @Override public final boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException { return helper.invoke(this, wait, glRunnable); diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 8f4105f98..6866374bc 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -45,7 +45,10 @@ import java.nio.IntBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.Map; +import java.util.Set; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.DynamicLookupHelper; @@ -59,12 +62,12 @@ import com.jogamp.gluegen.runtime.opengl.GLNameResolver; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.GLRendererQuirks; - import com.jogamp.nativewindow.AbstractGraphicsConfiguration; import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.nativewindow.ProxySurface; +import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GL2ES3; @@ -126,11 +129,13 @@ public abstract class GLContextImpl extends GLContext { * If GL >= 3.0 (ES or desktop) and not having {@link GLRendererQuirks#NoSurfacelessCtx}, * being evaluated if not surface-handle is null and not yet set at makeCurrent(..). */ - private boolean surfacelessOK = false; + private boolean isSurfaceless = false; private boolean pixelDataEvaluated; private int /* pixelDataInternalFormat, */ pixelDataFormat, pixelDataType; + private int currentSwapInterval; + protected GL gl; protected static final Object mappedContextTypeObjectLock; @@ -207,8 +212,9 @@ public abstract class GLContextImpl extends GLContext { boundFBOTarget[1] = 0; // read } - surfacelessOK = false; + isSurfaceless = false; pixelDataEvaluated = false; + currentSwapInterval = 0; super.resetStates(isInit); } @@ -536,7 +542,7 @@ public abstract class GLContextImpl extends GLContext { //---------------------------------------------------------------------- // - protected final boolean isSurfacelessOK() { return surfacelessOK; } + protected final boolean isSurfaceless() { return isSurfaceless; } /** * {@inheritDoc} @@ -607,7 +613,7 @@ public abstract class GLContextImpl extends GLContext { if ( drawable.isRealized() ) { lock.lock(); try { - if ( 0 == drawable.getHandle() && !surfacelessOK ) { + if ( 0 == drawable.getHandle() && !isSurfaceless ) { if( DEBUG ) { System.err.println(getThreadName() +": GLContext.makeCurrent: Surfaceless evaluate"); } @@ -671,7 +677,7 @@ public abstract class GLContextImpl extends GLContext { } if ( CONTEXT_NOT_CURRENT != res ) { // still locked! - if( 0 == drawable.getHandle() && !surfacelessOK ) { + if( 0 == drawable.getHandle() && !isSurfaceless ) { if( hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx) ) { throw new GLException(String.format("Surfaceless not supported due to quirk %s: %s", GLRendererQuirks.toString(GLRendererQuirks.NoSurfacelessCtx), toString())); @@ -679,15 +685,15 @@ public abstract class GLContextImpl extends GLContext { if( DEBUG ) { System.err.println(getThreadName() +": GLContext.makeCurrent: Surfaceless OK - validated"); } - surfacelessOK = true; + isSurfaceless = true; } setCurrent(this); if( CONTEXT_CURRENT_NEW == res ) { // check if the drawable's and the GL's GLProfile are equal // throws an GLException if not - drawable.getGLProfile().verifyEquality(gl.getGLProfile()); + // FIXME: drawable.getGLProfile().verifyEquality(gl.getGLProfile()); - glDebugHandler.init( isGL2GL3() && isGLDebugEnabled() ); + glDebugHandler.init( isGLDebugEnabled() ); if(DEBUG_GL) { setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ); @@ -802,28 +808,28 @@ public abstract class GLContextImpl extends GLContext { reqProfile = GLContext.CTX_PROFILE_COMPAT; isCompat = true; } - GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + final MappedGLVersion me = mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion, ctxOptions, glRendererQuirks); // Perform all required profile mappings if( isCompat ) { // COMPAT via non ARB - GLContext.mapAvailableGLVersion(device, reqMajor, GLContext.CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + mapAvailableGLVersion(device, reqMajor, GLContext.CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); if( reqMajor >= 4 ) { - GLContext.mapAvailableGLVersion(device, 3, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - GLContext.mapAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + mapAvailableGLVersion(device, 3, reqProfile, ctxVersion, ctxOptions, glRendererQuirks); + mapAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); } if( reqMajor >= 3 ) { - GLContext.mapAvailableGLVersion(device, 2, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + mapAvailableGLVersion(device, 2, reqProfile, ctxVersion, ctxOptions, glRendererQuirks); } } else { // CORE via non ARB, unlikely, however .. if( reqMajor >= 4 ) { - GLContext.mapAvailableGLVersion(device, 3, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + mapAvailableGLVersion(device, 3, reqProfile, ctxVersion, ctxOptions, glRendererQuirks); } } GLContext.setAvailableGLVersionsSet(device, true); if (DEBUG) { - System.err.println(getThreadName() + ": createContextOLD-MapVersionsAvailable HAVE: " + device+" -> "+reqMajor+"."+reqProfile+ " -> "+getGLVersion()); + System.err.println(getThreadName() + ": createContextOLD-MapGLVersions HAVE: " + me); } } } @@ -947,13 +953,13 @@ public abstract class GLContextImpl extends GLContext { { final AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice device = config.getScreen().getDevice(); - if (DEBUG) { - System.err.println(getThreadName() + ": createContextARB: mappedVersionsAvailableSet("+device.getConnection()+"): "+ - GLContext.getAvailableGLVersionsSet(device)); - } final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); final GLProfile glp = glCaps.getGLProfile(); + if (DEBUG) { + System.err.println(getThreadName() + ": createContextARB-MapGLVersions is SET ("+device.getConnection()+"): "+ + GLContext.getAvailableGLVersionsSet(device)); + } if ( !GLContext.getAvailableGLVersionsSet(device) ) { if( !mapGLVersions(device) ) { // none of the ARB context creation calls was successful, bail out @@ -965,7 +971,7 @@ public abstract class GLContextImpl extends GLContext { GLContext.getRequestMajorAndCompat(glp, reqMajorCTP); if(DEBUG) { - System.err.println(getThreadName() + ": createContextARB: Requested "+glp+" -> "+GLContext.getGLVersion(reqMajorCTP[0], 0, reqMajorCTP[1], null)); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions Requested "+glp+" -> "+GLContext.getGLVersion(reqMajorCTP[0], 0, reqMajorCTP[1], null)); } final int _major[] = { 0 }; final int _minor[] = { 0 }; @@ -975,7 +981,7 @@ public abstract class GLContextImpl extends GLContext { _major, _minor, _ctp)) { _ctp[0] |= additionalCtxCreationFlags; if(DEBUG) { - System.err.println(getThreadName() + ": createContextARB: Mapped "+GLContext.getGLVersion(_major[0], _minor[0], _ctp[0], null)); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions Mapped "+GLContext.getGLVersion(_major[0], _minor[0], _ctp[0], null)); } _ctx = createContextARBImpl(share, direct, _ctp[0], _major[0], _minor[0]); if(0!=_ctx) { @@ -987,8 +993,156 @@ public abstract class GLContextImpl extends GLContext { return _ctx; } + //---------------------------------------------------------------------- + // + + public static class MappedGLVersion { + public final AbstractGraphicsDevice device; + public final int reqMajorVersion; + public final int reqProfile; + public final VersionNumber ctxVersion; + public final int ctxOptions; + public final GLRendererQuirks quirks; + public final VersionNumber preCtxVersion; + public final int preCtxOptions; + public MappedGLVersion(final AbstractGraphicsDevice device, final int reqMajorVersion, final int reqProfile, + final VersionNumber ctxVersion, final int ctxOptions, final GLRendererQuirks quirks, + final VersionNumber preCtxVersion, final int preCtxOptions) { + this.device = device; + this.reqMajorVersion = reqMajorVersion; + this.reqProfile = reqProfile; + this.ctxVersion = ctxVersion; + this.ctxOptions = ctxOptions; + this.quirks = quirks; + this.preCtxVersion = preCtxVersion; + this.preCtxOptions = preCtxOptions; + } + public final String toString() { + return toString(new StringBuilder(), -1, -1, -1, -1).toString(); + } + public final StringBuilder toString(final StringBuilder sb, final int minMajor, final int minMinor, final int maxMajor, final int maxMinor) { + sb.append(device.toString()).append(" ").append(reqMajorVersion).append(" ("); + GLContext.getGLProfile(sb, reqProfile).append(")"); + if( minMajor >=0 && minMinor >=0 && maxMajor >= 0 && maxMinor >= 0) { + sb.append("[").append(minMajor).append(".").append(minMinor).append(" .. ").append(maxMajor).append(".").append(maxMinor).append("]"); + } + sb.append(": ["); + if( null != preCtxVersion ) { + GLContext.getGLVersion(sb, preCtxVersion, preCtxOptions, null); + } else { + sb.append("None"); + } + sb.append("] -> ["); + GLContext.getGLVersion(sb, ctxVersion, ctxOptions, null).append("]"); + return sb; + } + } + public static interface MappedGLVersionListener { + void glVersionMapped(final MappedGLVersion e); + } + private static MappedGLVersionListener mapGLVersionListener = null; + protected static synchronized void setMappedGLVersionListener(final MappedGLVersionListener mvl) { + mapGLVersionListener = mvl; + } + + /** + * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable(int,int)} not intended to be used by + * implementations. However, if {@link jogamp.opengl.GLContextImpl#createContextARB(long, boolean)} is not being used within + * {@link com.jogamp.opengl.GLDrawableFactory#getOrCreateSharedContext(com.jogamp.nativewindow.AbstractGraphicsDevice)}, + * GLProfile has to map the available versions. + * + * @param reqMajor Key Value either 1, 2, 3 or 4 + * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} + * @param resVersion the resulting version number + * @param resCtp the resulting context options + * @return the old mapped value + * + * @see #createContextARBMapVersionsAvailable + */ + protected static MappedGLVersion mapAvailableGLVersion(final AbstractGraphicsDevice device, + final int reqMajor, final int profile, + final VersionNumber resVersion, final int resCtp, + final GLRendererQuirks resQuirks) + { + final Integer preVal = mapAvailableGLVersion(device, reqMajor, profile, resVersion, resCtp); + final int[] preCtp = { 0 }; + final VersionNumber preVersion = null != preVal ? decomposeBits(preVal.intValue(), preCtp) : null; + final MappedGLVersion res = new MappedGLVersion(device, reqMajor, profile, resVersion, resCtp, resQuirks, preVersion, preCtp[0]); + if( null != mapGLVersionListener ) { + mapGLVersionListener.glVersionMapped(res); + } + return res; + } + private static Integer mapAvailableGLVersion(final AbstractGraphicsDevice device, + final int reqMajor, final int profile, final VersionNumber resVersion, int resCtp) + { + validateProfileBits(profile, "profile"); + validateProfileBits(resCtp, "resCtp"); + + if(FORCE_NO_FBO_SUPPORT) { + resCtp &= ~CTX_IMPL_FBO ; + } + if(DEBUG) { + System.err.println(getThreadName() + ": createContextARB-MapGLVersions MAP "+device+": "+reqMajor+" ("+GLContext.getGLProfile(new StringBuilder(), profile).toString()+ ") -> "+ + getGLVersion(resVersion.getMajor(), resVersion.getMinor(), resCtp, null)); + } + final String objectKey = getDeviceVersionAvailableKey(device, reqMajor, profile); + final Integer val = Integer.valueOf(composeBits(resVersion.getMajor(), resVersion.getMinor(), resCtp)); + synchronized(deviceVersionAvailable) { + return deviceVersionAvailable.put( objectKey, val ); + } + } + + + protected static void remapAvailableGLVersions(final AbstractGraphicsDevice fromDevice, final AbstractGraphicsDevice toDevice) { + if( fromDevice == toDevice || fromDevice.getUniqueID() == toDevice.getUniqueID() ) { + return; // NOP + } + synchronized(deviceVersionAvailable) { + if(DEBUG) { + System.err.println(getThreadName() + ": createContextARB-MapGLVersions REMAP "+fromDevice+" -> "+toDevice); + } + final IdentityHashMap<String, Integer> newDeviceVersionAvailable = new IdentityHashMap<String, Integer>(); + final Set<String> keys = deviceVersionAvailable.keySet(); + for(final Iterator<String> keyI = keys.iterator(); keyI.hasNext(); ) { + final String origKey = keyI.next(); + final Integer valI = deviceVersionAvailable.get(origKey); + if( null != valI ) { + if(DEBUG) { + final int[] ctp = { 0 }; + final VersionNumber version = decomposeBits(valI.intValue(), ctp); + System.err.println(" MapGLVersions REMAP OLD "+origKey+" -> "+GLContext.getGLVersion(new StringBuilder(), version, ctp[0], null).toString()); + } + newDeviceVersionAvailable.put(origKey, valI); + final int devSepIdx = origKey.lastIndexOf('-'); + if( 0 >= devSepIdx ) { + throw new InternalError("device-separator '-' at "+devSepIdx+" of "+origKey); + } + final String devUniqueID = origKey.substring(0, devSepIdx); + if( fromDevice.getUniqueID().equals(devUniqueID) ) { + final String profileReq = origKey.substring(devSepIdx); + final String newKey = (toDevice.getUniqueID()+profileReq).intern(); + if(DEBUG) { + System.err.println(" MapGLVersions REMAP NEW "+newKey+" -> (ditto)"); + } + newDeviceVersionAvailable.put(newKey, valI); + } + } + } + deviceVersionAvailable.clear(); + deviceVersionAvailable.putAll(newDeviceVersionAvailable); + GLContext.setAvailableGLVersionsSet(toDevice, true); + } + } + private final boolean mapGLVersions(final AbstractGraphicsDevice device) { synchronized (GLContext.deviceVersionAvailable) { + final boolean hasOpenGLESSupport = drawable.getFactory().hasOpenGLESSupport(); + final boolean hasOpenGLDesktopSupport = drawable.getFactory().hasOpenGLDesktopSupport(); + final boolean hasMinorVersionSupport = drawable.getFactoryImpl().hasMajorMinorCreateContextARB(); + if (DEBUG) { + System.err.println(getThreadName() + ": createContextARB-MapGLVersions START (GLDesktop "+hasOpenGLDesktopSupport+", GLES "+hasOpenGLESSupport+", minorVersion "+hasMinorVersionSupport+") on "+device); + } final long t0 = ( DEBUG ) ? System.nanoTime() : 0; boolean success = false; // Following GLProfile.GL_PROFILE_LIST_ALL order of profile detection { GL4bc, GL3bc, GL2, GL4, GL3, GL2GL3, GLES2, GL2ES2, GLES1, GL2ES1 } @@ -997,6 +1151,43 @@ public abstract class GLContextImpl extends GLContext { boolean hasGL2 = false; boolean hasGL4 = false; boolean hasGL3 = false; + boolean hasES3 = false; + boolean hasES2 = false; + boolean hasES1 = false; + + if( hasOpenGLESSupport && !GLProfile.disableOpenGLES ) { + if( !hasES3) { + hasES3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_ES, hasMinorVersionSupport); // ES3 + success |= hasES3; + if( hasES3 ) { + if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { + // Map hw-accel ES3 to all lower core profiles: ES2 + mapAvailableGLVersion(device, 2, CTX_PROFILE_ES, ctxVersion, ctxOptions, glRendererQuirks); + if( PROFILE_ALIASING ) { + hasES2 = true; + } + } + resetStates(false); // clean context states, since creation was temporary + } + } + if( !hasES2) { + hasES2 = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_ES, hasMinorVersionSupport); // ES2 + success |= hasES2; + if( hasES2 ) { + if( ctxVersion.getMajor() >= 3 && hasRendererQuirk(GLRendererQuirks.GLES3ViaEGLES2Config)) { + mapAvailableGLVersion(device, 3, CTX_PROFILE_ES, ctxVersion, ctxOptions, glRendererQuirks); + } + resetStates(false); // clean context states, since creation was temporary + } + } + if( !hasES1) { + hasES1 = createContextARBMapVersionsAvailable(device, 1, CTX_PROFILE_ES, hasMinorVersionSupport); // ES1 + success |= hasES1; + if( hasES1 ) { + resetStates(false); // clean context states, since creation was temporary + } + } + } // Even w/ PROFILE_ALIASING, try to use true core GL profiles // ensuring proper user behavior across platforms due to different feature sets! @@ -1006,31 +1197,31 @@ public abstract class GLContextImpl extends GLContext { /** * OSX 10.9 GLRendererQuirks.GL4NeedsGL3Request, quirk is added as usual @ setRendererQuirks(..) */ - if( !GLProfile.disableOpenGLCore && !hasGL4 && !hasGL3 ) { - hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3 + if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore && !hasGL4 && !hasGL3 ) { + hasGL3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE, hasMinorVersionSupport); // GL3 success |= hasGL3; if( hasGL3 ) { final boolean isHWAccel = 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ); if( isHWAccel && ctxVersion.getMajor() >= 4 ) { // Gotcha: Creating a '3.2' ctx delivers a >= 4 ctx. - GLContext.mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); hasGL4 = true; if(DEBUG) { - System.err.println("Quirk Triggerd: "+GLRendererQuirks.toString(GLRendererQuirks.GL4NeedsGL3Request)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions: Quirk Triggerd: "+GLRendererQuirks.toString(GLRendererQuirks.GL4NeedsGL3Request)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()); } } resetStates(false); // clean the context states, since creation was temporary } } } - if( !GLProfile.disableOpenGLCore ) { + if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore ) { if( !hasGL4 ) { - hasGL4 = createContextARBMapVersionsAvailable(4, CTX_PROFILE_CORE); // GL4 + hasGL4 = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_CORE, hasMinorVersionSupport); // GL4 success |= hasGL4; if( hasGL4 ) { if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { // Map hw-accel GL4 to all lower core profiles: GL3 - GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); if( PROFILE_ALIASING ) { hasGL3 = true; } @@ -1039,72 +1230,74 @@ public abstract class GLContextImpl extends GLContext { } } if( !hasGL3 ) { - hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3 + hasGL3 = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE, hasMinorVersionSupport); // GL3 success |= hasGL3; if( hasGL3 ) { resetStates(false); // clean this context states, since creation was temporary } } } - if( !hasGL4bc ) { - hasGL4bc = createContextARBMapVersionsAvailable(4, CTX_PROFILE_COMPAT); // GL4bc - success |= hasGL4bc; - if( hasGL4bc ) { - if( !hasGL4 ) { // last chance .. ignore hw-accel - GLContext.mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - hasGL4 = true; - } - if( !hasGL3 ) { // last chance .. ignore hw-accel - GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - hasGL3 = true; - } - if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { - // Map hw-accel GL4bc to all lower compatible profiles: GL3bc, GL2 - GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_COMPAT, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - GLContext.mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - if(PROFILE_ALIASING) { - hasGL3bc = true; - hasGL2 = true; + if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop ) { + if( !hasGL4bc ) { + hasGL4bc = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_COMPAT, hasMinorVersionSupport); // GL4bc + success |= hasGL4bc; + if( hasGL4bc ) { + if( !hasGL4 ) { // last chance .. ignore hw-accel + mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); + hasGL4 = true; + } + if( !hasGL3 ) { // last chance .. ignore hw-accel + mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); + hasGL3 = true; + } + if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { + // Map hw-accel GL4bc to all lower compatible profiles: GL3bc, GL2 + mapAvailableGLVersion(device, 3, CTX_PROFILE_COMPAT, ctxVersion, ctxOptions, glRendererQuirks); + mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion, ctxOptions, glRendererQuirks); + if(PROFILE_ALIASING) { + hasGL3bc = true; + hasGL2 = true; + } } + resetStates(false); // clean this context states, since creation was temporary } - resetStates(false); // clean this context states, since creation was temporary } - } - if( !hasGL3bc ) { - hasGL3bc = createContextARBMapVersionsAvailable(3, CTX_PROFILE_COMPAT); // GL3bc - success |= hasGL3bc; - if( hasGL3bc ) { - if(!hasGL3) { // last chance .. ignore hw-accel - GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - hasGL3 = true; - } - if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { - // Map hw-accel GL3bc to all lower compatible profiles: GL2 - GLContext.mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); - if(PROFILE_ALIASING) { - hasGL2 = true; + if( !hasGL3bc ) { + hasGL3bc = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_COMPAT, hasMinorVersionSupport); // GL3bc + success |= hasGL3bc; + if( hasGL3bc ) { + if(!hasGL3) { // last chance .. ignore hw-accel + mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks); + hasGL3 = true; } + if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) { + // Map hw-accel GL3bc to all lower compatible profiles: GL2 + mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion, ctxOptions, glRendererQuirks); + if(PROFILE_ALIASING) { + hasGL2 = true; + } + } + resetStates(false); // clean this context states, since creation was temporary } - resetStates(false); // clean this context states, since creation was temporary } - } - if( !hasGL2 ) { - hasGL2 = createContextARBMapVersionsAvailable(2, CTX_PROFILE_COMPAT); // GL2 - success |= hasGL2; - if( hasGL2 ) { - resetStates(false); // clean this context states, since creation was temporary + if( !hasGL2 ) { + hasGL2 = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_COMPAT, hasMinorVersionSupport); // GL2 + success |= hasGL2; + if( hasGL2 ) { + resetStates(false); // clean this context states, since creation was temporary + } } } if(success) { // only claim GL versions set [and hence detected] if ARB context creation was successful GLContext.setAvailableGLVersionsSet(device, true); - if(DEBUG) { - final long t1 = System.nanoTime(); - System.err.println("GLContextImpl.mapGLVersions: "+device+", profileAliasing: "+PROFILE_ALIASING+", total "+(t1-t0)/1e6 +"ms"); + } + if(DEBUG) { + final long t1 = System.nanoTime(); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions END (success "+success+") on "+device+", profileAliasing: "+PROFILE_ALIASING+", total "+(t1-t0)/1e6 +"ms"); + if( success ) { System.err.println(GLContext.dumpAvailableGLVersions(null).toString()); } - } else if (DEBUG) { - System.err.println(getThreadName() + ": createContextARB-MapVersions NONE for :"+device); } return success; } @@ -1114,38 +1307,61 @@ public abstract class GLContextImpl extends GLContext { * Note: Since context creation is temporary, caller need to issue {@link #resetStates(boolean)}, if creation was successful, i.e. returns true. * This method does not reset the states, allowing the caller to utilize the state variables. **/ - private final boolean createContextARBMapVersionsAvailable(final int reqMajor, final int reqProfile) { + private final boolean createContextARBMapVersionsAvailable(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile, + final boolean hasMinorVersionSupport) { long _context; int ctp = CTX_IS_ARB_CREATED | reqProfile; // To ensure GL profile compatibility within the JOGL application // we always try to map against the highest GL version, // so the user can always cast to the highest available one. - int majorMax, minorMax; - int majorMin, minorMin; + int maxMajor, maxMinor; + int minMajor, minMinor; final int major[] = new int[1]; final int minor[] = new int[1]; - if( CTX_PROFILE_ES == reqProfile ) { - majorMax=reqMajor; minorMax=GLContext.getMaxMinor(ctp, majorMax); - majorMin=reqMajor; minorMin=0; + if( hasMinorVersionSupport ) { + if( CTX_PROFILE_ES == reqProfile ) { + // ES3, ES2 or ES1 + maxMajor=reqMajor; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); + minMajor=reqMajor; minMinor=0; + } else { + if( 4 == reqMajor ) { + maxMajor=4; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); + minMajor=4; minMinor=0; + } else if( 3 == reqMajor ) { + maxMajor=3; maxMinor=GLContext.getMaxMinor(ctp, maxMajor); + minMajor=3; minMinor=1; + } else /* if( glp.isGL2() ) */ { + // our minimum desktop OpenGL runtime requirements are 1.1, + // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts + maxMajor=3; maxMinor=0; + minMajor=2; minMinor=0; + } + } } else { - if( 4 == reqMajor ) { - majorMax=4; minorMax=GLContext.getMaxMinor(ctp, majorMax); - majorMin=4; minorMin=0; - } else if( 3 == reqMajor ) { - majorMax=3; minorMax=GLContext.getMaxMinor(ctp, majorMax); - majorMin=3; minorMin=1; - } else /* if( glp.isGL2() ) */ { - // our minimum desktop OpenGL runtime requirements are 1.1, - // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts - majorMax=3; minorMax=0; - majorMin=2; minorMin=0; + if( CTX_PROFILE_ES == reqProfile ) { + // ES3, ES2 or ES1 + maxMajor=reqMajor; maxMinor=0; + minMajor=reqMajor; minMinor=0; + } else { + if( 4 == reqMajor ) { + maxMajor=4; maxMinor=0; + minMajor=4; minMinor=0; + } else if( 3 == reqMajor ) { + maxMajor=3; maxMinor=1; + minMajor=3; minMinor=1; + } else /* if( glp.isGL2() ) */ { + // our minimum desktop OpenGL runtime requirements are 1.1, + // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts + maxMajor=2; maxMinor=0; + minMajor=2; minMinor=0; + } } } _context = createContextARBVersions(0, true, ctp, - /* max */ majorMax, minorMax, - /* min */ majorMin, minorMin, + /* max */ maxMajor, maxMinor, + /* min */ minMajor, minMinor, /* res */ major, minor); if( 0 == _context && CTX_PROFILE_CORE == reqProfile && !PROFILE_ALIASING ) { @@ -1153,8 +1369,8 @@ public abstract class GLContextImpl extends GLContext { ctp &= ~CTX_PROFILE_CORE ; ctp |= CTX_OPTION_FORWARD ; _context = createContextARBVersions(0, true, ctp, - /* max */ majorMax, minorMax, - /* min */ majorMin, minorMin, + /* max */ maxMajor, maxMinor, + /* min */ minMajor, minMinor, /* res */ major, minor); if( 0 == _context ) { // Try a compatible one .. even though not requested .. last resort @@ -1162,25 +1378,24 @@ public abstract class GLContextImpl extends GLContext { ctp &= ~CTX_OPTION_FORWARD ; ctp |= CTX_PROFILE_COMPAT ; _context = createContextARBVersions(0, true, ctp, - /* max */ majorMax, minorMax, - /* min */ majorMin, minorMin, + /* max */ maxMajor, maxMinor, + /* min */ minMajor, minMinor, /* res */ major, minor); } } final boolean res; if( 0 != _context ) { - final AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); // ctxMajorVersion, ctxMinorVersion, ctxOptions is being set by // createContextARBVersions(..) -> setGLFunctionAvailbility(..) -> setContextVersion(..) - GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + final MappedGLVersion me = mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion, ctxOptions, glRendererQuirks); destroyContextARBImpl(_context); if (DEBUG) { - System.err.println(getThreadName() + ": createContextARB-MapVersionsAvailable HAVE: " +reqMajor+"."+reqProfile+ " -> "+getGLVersion()); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions HAVE "+me.toString(new StringBuilder(), minMajor, minMinor, maxMajor, maxMinor).toString()); } res = true; } else { if (DEBUG) { - System.err.println(getThreadName() + ": createContextARB-MapVersionsAvailable NOPE: "+reqMajor+"."+reqProfile); + System.err.println(getThreadName() + ": createContextARB-MapGLVersions NOPE "+device+", "+reqMajor+" ("+GLContext.getGLProfile(new StringBuilder(), reqProfile).toString()+ ") ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]"); } res = false; } @@ -1188,11 +1403,11 @@ public abstract class GLContextImpl extends GLContext { } private final long createContextARBVersions(final long share, final boolean direct, final int ctxOptionFlags, - final int majorMax, final int minorMax, - final int majorMin, final int minorMin, + final int maxMajor, final int maxMinor, + final int minMajor, final int minMinor, final int major[], final int minor[]) { - major[0]=majorMax; - minor[0]=minorMax; + major[0]=maxMajor; + minor[0]=maxMinor; long _context=0; int i=0; @@ -1200,7 +1415,7 @@ public abstract class GLContextImpl extends GLContext { if (DEBUG) { i++; System.err.println(getThreadName() + ": createContextARBVersions."+i+": share "+share+", direct "+direct+ - ", version "+major[0]+"."+minor[0]+", major["+majorMin+".."+majorMax+"], minor["+minorMin+".."+minorMax+"]"); + ", version "+major[0]+"."+minor[0]+" ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]"); } _context = createContextARBImpl(share, direct, ctxOptionFlags, major[0], minor[0]); @@ -1213,12 +1428,12 @@ public abstract class GLContextImpl extends GLContext { } } - } while ( ( major[0]>majorMin || major[0]==majorMin && minor[0] >minorMin ) && // #1 check whether version is above lower limit + } while ( ( major[0]>minMajor || major[0]==minMajor && minor[0] >minMinor ) && // #1 check whether version is above lower limit GLContext.decrementGLVersion(ctxOptionFlags, major, minor) // #2 decrement version ); if (DEBUG) { System.err.println(getThreadName() + ": createContextARBVersions.X: ctx "+toHexString(_context)+", share "+share+", direct "+direct+ - ", version "+major[0]+"."+minor[0]+", major["+majorMin+".."+majorMax+"], minor["+minorMin+".."+minorMax+"]"); + ", version "+major[0]+"."+minor[0]+" ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]"); } return _context; } @@ -1261,11 +1476,19 @@ public abstract class GLContextImpl extends GLContext { // Helpers for various context implementations // - private final Object createInstance(final GLProfile glp, final boolean glObject, final Object[] cstrArgs) { + private final boolean verifyInstance(final GLProfile glp, final String suffix, final Object instance) { + return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix); + } + private final Object createInstance(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption, + final boolean glObject, final Object[] cstrArgs) { + final String profileString = GLContext.getGLProfile(majorVersion, minorVersion, contextOption); + final GLProfile glp = GLProfile.get(adevice, profileString) ; return ReflectionUtil.createInstance(glp.getGLCtor(glObject), cstrArgs); } - - private final boolean verifyInstance(final GLProfile glp, final String suffix, final Object instance) { + private final boolean verifyInstance(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption, + final String suffix, final Object instance) { + final String profileString = GLContext.getGLProfile(majorVersion, minorVersion, contextOption); + final GLProfile glp = GLProfile.get(adevice, profileString) ; return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix); } @@ -1273,8 +1496,11 @@ public abstract class GLContextImpl extends GLContext { * Create the GL instance for this context, * requires valid {@link #getGLProcAddressTable()} result! */ - private final GL createGL(final GLProfile glp) { - final GL gl = (GL) createInstance(glp, true, new Object[] { glp, this } ); + private final GL createGL(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption) { + final String profileString = GLContext.getGLProfile(majorVersion, minorVersion, contextOption); + final GLProfile glp = GLProfile.get(adevice, profileString); + final GL gl = (GL) ReflectionUtil.createInstance(glp.getGLCtor(true), new Object[] { glp, this }); + //nal GL gl = (GL) createInstance(glp, true, new Object[] { glp, this } ); /* FIXME: refactor dependence on Java 2D / JOGL bridge if (tracker != null) { @@ -1348,34 +1574,53 @@ public abstract class GLContextImpl extends GLContext { } protected abstract Map<String, String> getExtensionNameMap() ; + /** + * Returns the DynamicLookupHelper + */ + public final GLDynamicLookupHelper getGLDynamicLookupHelper() { + return drawable.getFactoryImpl().getGLDynamicLookupHelper( ctxVersion.getMajor(), ctxOptions ); + } + public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) { + return drawable.getFactoryImpl().getGLDynamicLookupHelper( majorVersion, contextOptions ); + } + /** Helper routine which resets a ProcAddressTable generated by the - GLEmitter by looking up anew all of its function pointers. */ - protected final void resetProcAddressTable(final ProcAddressTable table) { + GLEmitter by looking up anew all of its function pointers + using the given {@link GLDynamicLookupHelper}. */ + protected final void resetProcAddressTable(final ProcAddressTable table, final GLDynamicLookupHelper dlh) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { - table.reset(getDrawableImpl().getGLDynamicLookupHelper() ); + table.reset( dlh ); return null; } } ); } - private final PrivilegedAction<Object> privInitGLGetPtrAction = new PrivilegedAction<Object>() { - @Override - public Object run() { - final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper(); - glDynLookupHelper.claimAllLinkPermission(); - try { - glGetStringPtr = glDynLookupHelper.dynamicLookupFunction("glGetString"); - glGetIntegervPtr = glDynLookupHelper.dynamicLookupFunction("glGetIntegerv"); - } finally { - glDynLookupHelper.releaseAllLinkPermission(); - } - return null; - } }; - private final boolean initGLRendererAndGLVersionStrings() { + /** + * Updates the platform's 'GLX' function cache + * @param contextFQN provides a fully qualified key of the context including device and GL profile + * @param dlh {@link GLDynamicLookupHelper} used to {@link #resetProcAddressTable(ProcAddressTable, GLDynamicLookupHelper)} instance. + */ + protected abstract void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh); + + private final boolean initGLRendererAndGLVersionStrings(final int majorVersion, final int contextOptions) { if( !glGetPtrInit ) { - AccessController.doPrivileged(privInitGLGetPtrAction); + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + final GLDynamicLookupHelper glDynLookupHelper = getGLDynamicLookupHelper(majorVersion, contextOptions); + if( null != glDynLookupHelper ) { + glDynLookupHelper.claimAllLinkPermission(); + try { + glGetStringPtr = glDynLookupHelper.dynamicLookupFunction("glGetString"); + glGetIntegervPtr = glDynLookupHelper.dynamicLookupFunction("glGetIntegerv"); + } finally { + glDynLookupHelper.releaseAllLinkPermission(); + } + } + return null; + } } ); glGetPtrInit = true; } if( 0 == glGetStringPtr || 0 == glGetIntegervPtr ) { @@ -1521,7 +1766,7 @@ public abstract class GLContextImpl extends GLContext { final VersionNumber reqGLVersion = new VersionNumber(major, minor, 0); final VersionNumber hasGLVersionByString; { - final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings(); + final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings(major, ctxProfileBits); if( !initGLRendererAndGLVersionStringsOK ) { final String errMsg = "Intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null); if( strictMatch ) { @@ -1557,50 +1802,51 @@ public abstract class GLContextImpl extends GLContext { { // Validate the requested version w/ the GL-version from an integer query, // as supported by GL [ES] >= 3.0 implementation. - final VersionNumber hasGLVersionByInt; - { - final int[] glIntMajor = new int[] { 0 }, glIntMinor = new int[] { 0 }; - getGLIntVersion(glIntMajor, glIntMinor); - hasGLVersionByInt = new VersionNumber(glIntMajor[0], glIntMinor[0], 0); - } - if (DEBUG) { - System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Version verification (Int): String "+glVersion+", Number(Int) "+hasGLVersionByInt); - } - + // // Only validate integer based version if: // - ctx >= 3.0 is requested _or_ string-version >= 3.0 // - _and_ a valid int version was fetched, // otherwise cont. w/ version-string method -> 3.0 > Version || Version > MAX! // - if ( ( major >= 3 || hasGLVersionByString.compareTo(Version3_0) >= 0 ) && - GLContext.isValidGLVersion(ctxProfileBits, hasGLVersionByInt.getMajor(), hasGLVersionByInt.getMinor()) ) { - // Strict Match (GLVersionMapping): - // Relaxed match for versions ( !isES && major < 3 ) requests, last resort! - // Otherwise: - // - fail if hasVersion < reqVersion (desktop and ES) - // - fail if ES major-version mismatch: - // - request 1, >= 3 must be equal - // - request 2 must be [2..3] - // - final int hasMajor = hasGLVersionByInt.getMajor(); - if( strictMatch && - ( ( ( isES || major >= 3 ) && hasGLVersionByInt.compareTo(reqGLVersion) < 0 ) || - ( isES && - ( - ( 2 == major && ( 2 > hasMajor || hasMajor > 3 ) ) || // 2 -> [2..3] - ( ( 1 == major || 3 <= major ) && major != hasMajor ) // 1,3,.. -> equal - ) - ) - ) ) { - if(DEBUG) { - System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (Int): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByInt); + final VersionNumber hasGLVersionByInt; + if ( major >= 3 || hasGLVersionByString.compareTo(Version3_0) >= 0 ) { + final int[] glIntMajor = new int[] { 0 }, glIntMinor = new int[] { 0 }; + getGLIntVersion(glIntMajor, glIntMinor); + hasGLVersionByInt = new VersionNumber(glIntMajor[0], glIntMinor[0], 0); + if (DEBUG) { + System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Version verification (Int): String "+glVersion+", Number(Int) "+hasGLVersionByInt); + } + if ( GLContext.isValidGLVersion(ctxProfileBits, hasGLVersionByInt.getMajor(), hasGLVersionByInt.getMinor()) ) { + // Strict Match (GLVersionMapping): + // Relaxed match for versions ( !isES && major < 3 ) requests, last resort! + // Otherwise: + // - fail if hasVersion < reqVersion (desktop and ES) + // - fail if ES major-version mismatch: + // - request 1, >= 3 must be equal + // - request 2 must be [2..3] + // + final int hasMajor = hasGLVersionByInt.getMajor(); + if( strictMatch && + ( ( ( isES || major >= 3 ) && hasGLVersionByInt.compareTo(reqGLVersion) < 0 ) || + ( isES && + ( + ( 2 == major && ( 2 > hasMajor || hasMajor > 3 ) ) || // 2 -> [2..3] + ( ( 1 == major || 3 <= major ) && major != hasMajor ) // 1,3,.. -> equal + ) + ) + ) ) { + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (Int): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByInt); + } + return false; } - return false; + // Use returned GL version! + major = hasGLVersionByInt.getMajor(); + minor = hasGLVersionByInt.getMinor(); + versionGL3IntOK = true; + } else { + versionGL3IntOK = false; } - // Use returned GL version! - major = hasGLVersionByInt.getMajor(); - minor = hasGLVersionByInt.getMinor(); - versionGL3IntOK = true; } else { versionGL3IntOK = false; } @@ -1668,7 +1914,8 @@ public abstract class GLContextImpl extends GLContext { } if( major < 2 ) { // there is no ES2/3-compat for a profile w/ major < 2 - ctxProfileBits &= ~ ( GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_ES3_COMPAT | GLContext.CTX_IMPL_ES31_COMPAT ) ; + ctxProfileBits &= ~ ( GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_ES3_COMPAT | + GLContext.CTX_IMPL_ES31_COMPAT | GLContext.CTX_IMPL_ES32_COMPAT ) ; } if(!isCurrentContextHardwareRasterizer()) { @@ -1692,43 +1939,72 @@ public abstract class GLContextImpl extends GLContext { if (DEBUG) { System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)); } - - updateGLXProcAddressTable(); + final GLDynamicLookupHelper dynamicLookup = getGLDynamicLookupHelper(major, ctxProfileBits); + if( null == dynamicLookup ) { + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, No GLDynamicLookupHelper for request: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)); + } + return false; + } + updateGLXProcAddressTable(contextFQN, dynamicLookup); // // UpdateGLProcAddressTable functionality // _and_ setup GL instance, which ctor requires valid getGLProcAddressTable() result! // { - final GLProfile glp = drawable.getGLProfile(); + final GLProfile glp = drawable.getGLProfile(); // !withinGLVersionsMapping ProcAddressTable table = null; synchronized(mappedContextTypeObjectLock) { table = mappedGLProcAddress.get( contextFQN ); - if(null != table && !verifyInstance(glp, "ProcAddressTable", table)) { - throw new GLException("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ - ") -> "+ table.getClass().getName()+" not matching "+glp.getGLImplBaseClassName()); + if(null != table) { + if( !verifyInstance(adevice, major, minor, ctxProfileBits, "ProcAddressTable", table) ) { + throw new GLException("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+ toHexString(table.hashCode()) +" not matching "+table.getClass().getName()); + } + if( !withinGLVersionsMapping && !verifyInstance(glp, "ProcAddressTable", table) ) { + throw new GLException("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+ toHexString(table.hashCode()) +": "+table.getClass().getName()+" not matching "+glp.getGLImplBaseClassName()+"/"+glp); + } } } if(null != table) { glProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+") -> "+toHexString(table.hashCode())); + if( withinGLVersionsMapping ) { + System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+ toHexString(table.hashCode()) +": "+table.getClass().getName()); + } else { + System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+ toHexString(table.hashCode()) +": "+table.getClass().getName()+" -> "+glp.getGLImplBaseClassName()); + } } } else { - glProcAddressTable = (ProcAddressTable) createInstance(glp, false, + glProcAddressTable = (ProcAddressTable) createInstance(adevice, major, minor, ctxProfileBits, false, new Object[] { new GLProcAddressResolver() } ); - resetProcAddressTable( glProcAddressTable ); + resetProcAddressTable(glProcAddressTable, dynamicLookup); + synchronized(mappedContextTypeObjectLock) { mappedGLProcAddress.put(contextFQN, glProcAddressTable); if(DEBUG) { - System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+toHexString(glProcAddressTable.hashCode())); + if( withinGLVersionsMapping ) { + System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+toHexString(glProcAddressTable.hashCode()) +": "+glProcAddressTable.getClass().getName()); + } else { + System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+toHexString(glProcAddressTable.hashCode()) +": "+glProcAddressTable.getClass().getName()+" -> "+glp.getGLImplBaseClassName()); + } } } } - if( null == this.gl || !verifyInstance(glp, "Impl", this.gl) ) { - setGL( createGL( glp ) ); + if( null == this.gl || !verifyInstance(adevice, major, minor, ctxProfileBits, "Impl", this.gl) ) { + setGL( createGL( adevice, major, minor, ctxProfileBits ) ); + } + if( !withinGLVersionsMapping && !verifyInstance(glp, "Impl", this.gl) ) { + throw new GLException("GLContext GL Object mismatch: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+": "+this.gl.getClass().getName()+" not matching "+glp.getGLImplBaseClassName()+"/"+glp); } } @@ -1762,7 +2038,9 @@ public abstract class GLContextImpl extends GLContext { if( major >= 3 ) { ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ; ctxProfileBits |= CTX_IMPL_FBO; - if( minor >= 1 ) { + if( minor >= 2 ) { + ctxProfileBits |= CTX_IMPL_ES32_COMPAT | CTX_IMPL_ES31_COMPAT; + } else if( minor >= 1 ) { ctxProfileBits |= CTX_IMPL_ES31_COMPAT; } } else if( major >= 2 ) { @@ -1770,10 +2048,15 @@ public abstract class GLContextImpl extends GLContext { ctxProfileBits |= CTX_IMPL_FBO; } } else if( ( major > 4 || major == 4 && minor >= 5 ) || - ( ( major > 3 || major == 3 && minor >= 1 ) && isExtensionAvailable( GLExtensions.ARB_ES3_1_compatibility ) ) ) { - // See GLContext.isGLES31CompatibleAvailable(..)/isGLES31Compatible() - // Includes [ GL ≥ 4.5, GL ≥ 3.1 w/ GL_ARB_ES3_1_compatibility and GLES ≥ 3.1 ] - ctxProfileBits |= CTX_IMPL_ES31_COMPAT | CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ; + ( major > 3 || major == 3 && minor >= 1 ) ) { + // See GLContext.isGLES31CompatibleAvailable(..)/isGLES3[12]Compatible() + // Includes [ GL ≥ 4.5, GL ≥ 3.1 w/ GL_ARB_ES3_[12]_compatibility and GLES ≥ 3.[12] ] + if( isExtensionAvailable( GLExtensions.ARB_ES3_2_compatibility ) ) { + ctxProfileBits |= CTX_IMPL_ES32_COMPAT | CTX_IMPL_ES31_COMPAT; + } else if( isExtensionAvailable( GLExtensions.ARB_ES3_1_compatibility ) ) { + ctxProfileBits |= CTX_IMPL_ES31_COMPAT; + } + ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT; ctxProfileBits |= CTX_IMPL_FBO; } else if( ( major > 4 || major == 4 && minor >= 3 ) || ( ( major > 3 || major == 3 && minor >= 1 ) && isExtensionAvailable( GLExtensions.ARB_ES3_compatibility ) ) ) { @@ -1813,6 +2096,31 @@ public abstract class GLContextImpl extends GLContext { return true; } + private static final void addStickyQuirkAlways(final AbstractGraphicsDevice adevice, + final GLRendererQuirks quirks, + final int quirk, + final boolean withinGLVersionsMapping) { + quirks.addQuirk( quirk ); + if( withinGLVersionsMapping ) { + // Thread safe due to single threaded initialization! + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + } else { + // FIXME: Remove when moving EGL/ES to ARB ctx creation + synchronized(GLContextImpl.class) { + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + } + } + } + private static final void addStickyQuirkAtMapping(final AbstractGraphicsDevice adevice, + final GLRendererQuirks quirks, + final int quirk, + final boolean withinGLVersionsMapping) { + quirks.addQuirk( quirk ); + if( withinGLVersionsMapping ) { + // Thread safe due to single threaded initialization! + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + } + } private final void setRendererQuirks(final AbstractGraphicsDevice adevice, final GLDrawableFactoryImpl factory, final int reqMajor, final int reqMinor, final int reqCTP, final int major, final int minor, final int ctp, final VersionNumberString vendorVersion, @@ -1822,10 +2130,10 @@ public abstract class GLContextImpl extends GLContext { final String MesaRendererIntelsp = "Intel(R)"; final boolean hwAccel = 0 == ( ctp & GLContext.CTX_IMPL_ACCEL_SOFT ); final boolean compatCtx = 0 != ( ctp & GLContext.CTX_PROFILE_COMPAT ); - final boolean esCtx = 0 != ( ctp & GLContext.CTX_PROFILE_ES ); + final boolean isES = 0 != ( ctp & GLContext.CTX_PROFILE_ES ); final boolean isX11 = NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true); final boolean isWindows = Platform.getOSType() == Platform.OSType.WINDOWS; - final boolean isDriverMesa = glRenderer.contains(MesaSP) || glRenderer.contains("Gallium "); + final boolean isDriverMesa = glRenderer.contains(MesaSP) || glRenderer.contains("Gallium ") || glVersion.contains(MesaSP); final boolean isDriverATICatalyst; final boolean isDriverNVIDIAGeForce; @@ -1845,22 +2153,13 @@ public abstract class GLContextImpl extends GLContext { // // General Quirks // - if( esCtx ) { + if( isES ) { if( 2 == reqMajor && 2 < major ) { final int quirk = GLRendererQuirks.GLES3ViaEGLES2Config; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES req "+reqMajor+" and 2 < "+major); } - quirks.addQuirk( quirk ); - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } else { - // FIXME: Remove when moving EGL/ES to ARB ctx creation - synchronized(GLContextImpl.class) { - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } - } + addStickyQuirkAlways(adevice, quirks, quirk, withinGLVersionsMapping); } } if( GLProfile.disableSurfacelessContext ) { @@ -1868,32 +2167,14 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: disabled"); } - quirks.addQuirk( quirk ); - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } else { - // FIXME: Remove when moving EGL/ES to ARB ctx creation - synchronized(GLContextImpl.class) { - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } - } + addStickyQuirkAlways(adevice, quirks, quirk, withinGLVersionsMapping); } if( GLProfile.disableOpenGLARBContext ) { final int quirk = GLRendererQuirks.NoARBCreateContext; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: disabled"); } - quirks.addQuirk( quirk ); - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } else { - // FIXME: Remove when moving EGL/ES to ARB ctx creation - synchronized(GLContextImpl.class) { - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } - } + addStickyQuirkAlways(adevice, quirks, quirk, withinGLVersionsMapping); } // @@ -1922,11 +2203,7 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", req "+reqMajor+"."+reqMinor); } - quirks.addQuirk( quirk ); - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } + addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping); } if( isDriverNVIDIAGeForce ) { final VersionNumber osxVersionNVFlushClean = new VersionNumber(10,7,3); // < OSX 10.7.3 w/ NV needs glFlush @@ -1984,11 +2261,7 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", [Vendor "+glVendor+", Renderer "+glRenderer+" and Version "+glVersion+"]"); } - quirks.addQuirk( quirk ); - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } + addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping); } } } else if( isDriverIntel && glRenderer.equals("Intel Bear Lake B") ) { @@ -2054,6 +2327,17 @@ public abstract class GLContextImpl extends GLContext { } } } + if( isDriverNVIDIAGeForce ) { + // Bug 1200: Crash on GNU/Linux x86_64 'NVidia beta driver 355.06' @ probeSurfacelessCtx + // final VersionNumber nvSafeVersion = new VersionNumber(356, 0, 0); // FIXME: Add safe version! + if( !isES && !(adevice instanceof EGLGraphicsDevice) /* && vendorVersion.compareTo(nvSafeVersion) < 0 */ ) { + final int quirk = GLRendererQuirks.NoSurfacelessCtx; + if(DEBUG) { + System.err.print("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: !ES, !EGL, Vendor " + glVendor +", X11 Renderer " + glRenderer+", Version=[vendor " + vendorVersion + ", GL " + glVersion+"]"); + } + addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping); + } + } } @@ -2063,8 +2347,10 @@ public abstract class GLContextImpl extends GLContext { if( isDriverMesa ) { final VersionNumber mesaSafeFBOVersion = new VersionNumber(8, 0, 0); final VersionNumber mesaIntelBuggySharedCtx921 = new VersionNumber(9, 2, 1); + final VersionNumber mesaSafeDoubleBufferedPBuffer = new VersionNumber(18, 2, 2); // Mesa 18.2.2 + final VersionNumber mesaSafeSetSwapIntervalPostRetarget = mesaSafeDoubleBufferedPBuffer; // Mesa 18.2.2 - { + if( vendorVersion.compareTo(mesaSafeSetSwapIntervalPostRetarget) < 0 ) { final int quirk = GLRendererQuirks.NoSetSwapIntervalPostRetarget; if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); @@ -2073,11 +2359,13 @@ public abstract class GLContextImpl extends GLContext { } if( hwAccel ) { // hardware-acceleration - final int quirk = GLRendererQuirks.NoDoubleBufferedPBuffer; - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); + if( vendorVersion.compareTo(mesaSafeDoubleBufferedPBuffer) < 0 ) { + final int quirk = GLRendererQuirks.NoDoubleBufferedPBuffer; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer); + } + quirks.addQuirk( quirk ); } - quirks.addQuirk( quirk ); } else { // software if( vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { // FIXME: Is it fixed in >= 8.0.0 ? @@ -2111,11 +2399,7 @@ public abstract class GLContextImpl extends GLContext { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Vendor "+glVendor); } - quirks.addQuirk( quirk ); - if( withinGLVersionsMapping ) { - // Thread safe due to single threaded initialization! - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - } + addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping); } if( isWindows && glRenderer.contains("SVGA3D") && vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { final int quirk = GLRendererQuirks.NoFullFBOSupport; @@ -2157,7 +2441,7 @@ public abstract class GLContextImpl extends GLContext { if( !GLRendererQuirks.areSameStickyDevice(factoryDefaultDevice, adevice) ) { GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, quirks); } - if( esCtx ) { + if( isES ) { final AbstractGraphicsDevice eglFactoryDefaultDevice = GLDrawableFactory.getEGLFactory().getDefaultDevice(); if( !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, adevice) && !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, factoryDefaultDevice) ) { @@ -2233,11 +2517,6 @@ public abstract class GLContextImpl extends GLContext { return isHardwareRasterizer; } - /** - * Updates the platform's 'GLX' function cache - */ - protected abstract void updateGLXProcAddressTable(); - protected abstract StringBuilder getPlatformExtensionsStringImpl(); @Override @@ -2262,7 +2541,10 @@ public abstract class GLContextImpl extends GLContext { } // dynamic function lookup at last incl name aliasing (not cached) - final DynamicLookupHelper dynLookup = getDrawableImpl().getGLDynamicLookupHelper(); + final DynamicLookupHelper dynLookup = getGLDynamicLookupHelper(ctxVersion.getMajor(), ctxOptions); + if( null == dynLookup ) { + throw new GLException("No GLDynamicLookupHelper for "+this); + } final String tmpBase = GLNameResolver.normalizeVEN(GLNameResolver.normalizeARB(glFunctionName, true), true); return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override @@ -2378,6 +2660,40 @@ public abstract class GLContextImpl extends GLContext { } //---------------------------------------------------------------------- + // SwapBuffer + + @Override + public final boolean setSwapInterval(final int interval) throws GLException { + validateCurrent(); + return setSwapIntervalNC(interval); + } + protected final boolean setSwapIntervalNC(final int interval) throws GLException { + if( !drawableRetargeted || + !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget) + ) + { + final Integer usedInterval = setSwapIntervalImpl2(interval); + if( null != usedInterval ) { + currentSwapInterval = usedInterval.intValue(); + return true; + } + } + return false; + } + protected abstract Integer setSwapIntervalImpl2(final int interval); + + @Override + public final int getSwapInterval() { + return currentSwapInterval; + } + @Override + protected final void setDefaultSwapInterval() { + currentSwapInterval = 0; + setSwapIntervalNC(1); + } + + + //---------------------------------------------------------------------- // Helpers for buffer object optimizations public final GLBufferObjectTracker getBufferObjectTracker() { @@ -2536,8 +2852,8 @@ public abstract class GLContextImpl extends GLContext { @Override public final void glDebugMessageControl(final int source, final int type, final int severity, final int count, final IntBuffer ids, final boolean enabled) { - if(glDebugHandler.isExtensionARB()) { - gl.getGL2GL3().glDebugMessageControl(source, type, severity, count, ids, enabled); + if(glDebugHandler.isExtensionKHRARB()) { + gl.getGL2ES2().glDebugMessageControl(source, type, severity, count, ids, enabled); } else if(glDebugHandler.isExtensionAMD()) { gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, enabled); } @@ -2545,8 +2861,8 @@ public abstract class GLContextImpl extends GLContext { @Override public final void glDebugMessageControl(final int source, final int type, final int severity, final int count, final int[] ids, final int ids_offset, final boolean enabled) { - if(glDebugHandler.isExtensionARB()) { - gl.getGL2GL3().glDebugMessageControl(source, type, severity, count, ids, ids_offset, enabled); + if(glDebugHandler.isExtensionKHRARB()) { + gl.getGL2ES2().glDebugMessageControl(source, type, severity, count, ids, ids_offset, enabled); } else if(glDebugHandler.isExtensionAMD()) { gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, ids_offset, enabled); } @@ -2555,8 +2871,8 @@ public abstract class GLContextImpl extends GLContext { @Override public final void glDebugMessageInsert(final int source, final int type, final int id, final int severity, final String buf) { final int len = (null != buf) ? buf.length() : 0; - if(glDebugHandler.isExtensionARB()) { - gl.getGL2GL3().glDebugMessageInsert(source, type, id, severity, len, buf); + if(glDebugHandler.isExtensionKHRARB()) { + gl.getGL2ES2().glDebugMessageInsert(source, type, id, severity, len, buf); } else if(glDebugHandler.isExtensionAMD()) { gl.getGL2GL3().glDebugMessageInsertAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, id, len, buf); } diff --git a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java index cd31d02fd..fb4529da4 100644 --- a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java +++ b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java @@ -61,8 +61,9 @@ import com.jogamp.opengl.GLExtensions; public class GLDebugMessageHandler { private static final boolean DEBUG = Debug.debug("GLDebugMessageHandler"); - private static final int EXT_ARB = 1; - private static final int EXT_AMD = 2; + private static final int EXT_KHR = 1; + private static final int EXT_ARB = 2; + private static final int EXT_AMD = 3; static { if ( !initIDs0() ) { @@ -75,6 +76,7 @@ public class GLDebugMessageHandler { // licefycle: init - EOL private String extName; + private String extSuffix; private int extType; private long glDebugMessageCallbackProcAddress; private boolean extAvailable; @@ -92,6 +94,7 @@ public class GLDebugMessageHandler { this.listenerImpl = new ListenerSyncedImplStub<GLDebugListener>(); this.glDebugMessageCallbackProcAddress = 0; this.extName = null; + this.extSuffix = null; this.extType = 0; this.extAvailable = false; this.handle = 0; @@ -143,43 +146,68 @@ public class GLDebugMessageHandler { } return; } - if( ctx.isExtensionAvailable(GLExtensions.ARB_debug_output) ) { + if( ctx.isExtensionAvailable(GLExtensions.GL_KHR_debug) ) { + extName = GLExtensions.GL_KHR_debug; + extSuffix = ctx.isGLES() ? "KHR" : ""; // See SPEC! + extType = EXT_KHR; + } else if( ctx.isExtensionAvailable(GLExtensions.ARB_debug_output) ) { extName = GLExtensions.ARB_debug_output; + extSuffix = "ARB"; extType = EXT_ARB; } else if( ctx.isExtensionAvailable(GLExtensions.AMD_debug_output) ) { extName = GLExtensions.AMD_debug_output; + extSuffix = "AMD"; extType = EXT_AMD; } - if(DEBUG) { - System.err.println("GLDebugMessageHandler: Using extension: <"+extName+">"); + + // Validate GL Profile, just to be sure + switch(extType) { + case EXT_KHR: + if( !ctx.isGL2ES2() ) { + if(DEBUG) { + System.err.println("Non GL2ES2 context not supported, has "+ctx.getGLVersion()); + } + extType = 0; + } + break; + case EXT_ARB: + // fall through intended + case EXT_AMD: + if( !ctx.isGL2GL3() ) { + if(DEBUG) { + System.err.println("Non GL2GL3 context not supported, has "+ctx.getGLVersion()); + } + extType = 0; + } + break; } if(0 == extType) { + extName = null; + extSuffix = null; if(DEBUG) { System.err.println("GLDebugMessageHandler: No extension available! "+ctx.getGLVersion()); System.err.println("GL_EXTENSIONS "+ctx.getGLExtensionCount()); System.err.println(ctx.getGLExtensionsString()); } return; + } else if(DEBUG) { + System.err.println("GLDebugMessageHandler: Using extension: <"+extName+"> with suffix <"+extSuffix+">"); } final ProcAddressTable procAddressTable = ctx.getGLProcAddressTable(); - if( !ctx.isGLES1() && !ctx.isGLES2() ) { - switch(extType) { - case EXT_ARB: - glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallbackARB"); - break; - case EXT_AMD: - glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallbackAMD"); - break; - } - } else { - glDebugMessageCallbackProcAddress = 0; - if(DEBUG) { - System.err.println("Non desktop context not supported"); - } + switch(extType) { + case EXT_KHR: + glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallback"+extSuffix); + break; + case EXT_ARB: + glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallback"+extSuffix); + break; + case EXT_AMD: + glDebugMessageCallbackProcAddress = getAddressFor(procAddressTable, "glDebugMessageCallback"+extSuffix); + break; } - extAvailable = 0 < extType && null != extName && 0 != glDebugMessageCallbackProcAddress; + extAvailable = 0 < extType && null != extName && null != extSuffix && 0 != glDebugMessageCallbackProcAddress; if(DEBUG) { System.err.println("GLDebugMessageHandler: extAvailable: "+extAvailable+", glDebugMessageCallback* : 0x"+Long.toHexString(glDebugMessageCallbackProcAddress)); @@ -203,12 +231,20 @@ public class GLDebugMessageHandler { return extName; } + public final boolean isExtensionKHRARB() { + return EXT_KHR == extType || EXT_ARB == extType; + } + + public final boolean isExtensionKHR() { + return EXT_KHR == extType; + } + public final boolean isExtensionARB() { - return extName == GLExtensions.ARB_debug_output; + return EXT_ARB == extType; } public final boolean isExtensionAMD() { - return extName == GLExtensions.AMD_debug_output; + return EXT_AMD == extType; } /** @@ -226,7 +262,7 @@ public class GLDebugMessageHandler { } } private final void setSynchronousImpl() { - if(isExtensionARB()) { + if(isExtensionKHRARB()) { if(synchronous) { ctx.getGL().glEnable(GL2ES2.GL_DEBUG_OUTPUT_SYNCHRONOUS); } else { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index b7f861e13..dfe6bdd9f 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -230,6 +230,15 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { } /** + * Method returns {@code true} if underlying {@link #createContextARBImpl(long, boolean, int, int, int) <i>ARB context creation</i>} + * supports {@code major} and {@code minor} version number. + * <p> + * Otherwise only the {@code major} version number is supported for context creation. + * </p> + */ + public abstract boolean hasMajorMinorCreateContextARB(); + + /** * 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. @@ -245,12 +254,11 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { } /** - * Returns the GLDynamicLookupHelper - * @param profileName if EGL/ES, profile <code>1</code> refers to ES1 and <code>2</code> to ES2, - * otherwise the profile is ignored. - * @throws GLException if no DynamicLookupHelper is installed + * Returns the GLDynamicLookupHelper if installed, otherwise {@code null}. + * @param majorVersion the major OpenGL profile version + * @param contextOptions the context profile options */ - public abstract GLDynamicLookupHelper getGLDynamicLookupHelper(final String profileName) throws GLException; + public abstract GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions); //--------------------------------------------------------------------------- // Dispatching GLDrawable construction in respect to the NativeSurface Capabilities diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index e9ee46a51..e4b5eae5c 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -61,6 +61,7 @@ import com.jogamp.opengl.GLFBODrawable; import com.jogamp.opengl.GLRunnable; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.PropertyAccess; /** Encapsulates the implementation of most of the GLAutoDrawable's @@ -75,6 +76,8 @@ public class GLDrawableHelper { } protected static final boolean DEBUG = GLDrawableImpl.DEBUG; + private static final boolean DEBUG_SETCLEAR = GLContext.DEBUG_GL || DEBUG; + private final Object listenersLock = new Object(); private final ArrayList<GLEventListener> listeners = new ArrayList<GLEventListener>(); private final HashSet<GLEventListener> listenersToBeInit = new HashSet<GLEventListener>(); @@ -637,10 +640,10 @@ public class GLDrawableHelper { } } - private final void init(final GLEventListener l, final GLAutoDrawable drawable, final boolean sendReshape, final boolean setViewport) { + private final void init(final GLEventListener l, final GLAutoDrawable drawable, final boolean sendReshape) { l.init(drawable); if(sendReshape) { - reshape(l, drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), setViewport, false /* checkInit */); + l.reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); } } @@ -649,6 +652,7 @@ public class GLDrawableHelper { * @param sendReshape set to true if the subsequent display call won't reshape, otherwise false to avoid double reshape. **/ public final void init(final GLAutoDrawable drawable, final boolean sendReshape) { + setViewportAndClear(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); synchronized(listenersLock) { final ArrayList<GLEventListener> _listeners = listeners; final int listenerCount = _listeners.size(); @@ -660,11 +664,8 @@ public class GLDrawableHelper { // This may happen not just for initial setup, but for ctx recreation due to resource change (drawable/window), // hence it must be called unconditional, always. listenersToBeInit.remove(listener); // remove if exist, avoiding dbl init - init( listener, drawable, sendReshape, 0==i /* setViewport */); + init(listener, drawable, sendReshape); } - } else { - // Expose same GL initialization if not using any GLEventListener - drawable.getGL().glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); } } } @@ -686,7 +687,7 @@ public class GLDrawableHelper { // GLEventListener may need to be init, // in case this one is added after the realization of the GLAutoDrawable if( listenersToBeInit.remove(listener) ) { - init( listener, drawable, true /* sendReshape */, listenersToBeInit.size() + 1 == listenerCount /* setViewport if 1st init */ ); + init( listener, drawable, true /* sendReshape */ ); } listener.display(drawable); } @@ -711,41 +712,43 @@ public class GLDrawableHelper { // GLEventListener may need to be init, // in case this one is added after the realization of the GLAutoDrawable if( listenersToBeInit.remove(listener) ) { - init( listener, drawable, true /* sendReshape */, listenersToBeInit.size() + 1 == listenerCount /* setViewport if 1st init */ ); + init( listener, drawable, true /* sendReshape */ ); } action.run(drawable, listener); } } } - private final void reshape(final GLEventListener listener, final GLAutoDrawable drawable, - final int x, final int y, final int width, final int height, final boolean setViewport, final boolean checkInit) { - if(checkInit) { - // GLEventListener may need to be init, - // in case this one is added after the realization of the GLAutoDrawable - synchronized(listenersLock) { - if( listenersToBeInit.remove(listener) ) { - listener.init(drawable); - } - } - } - if(setViewport) { - if( GLContext.DEBUG_GL || DEBUG ) { - final int glerr0 = drawable.getGL().glGetError(); - if( GL.GL_NO_ERROR != glerr0 ) { - System.err.println("Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); - ExceptionUtils.dumpStack(System.err); - } - } - drawable.getGL().glViewport(x, y, width, height); - } - listener.reshape(drawable, x, y, width, height); + /** + * Bug 1206: Security: Clear exposed framebuffer after creation and before visibility + * - Clear framebuffer after setting viewport + * - Since we only attempt to help against leaking un-initialized framebuffer content + * not against user-app faults, we do not clear a 2nd-buffer (double-buffering). + */ + private final void setViewportAndClear(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + final GL gl = drawable.getGL(); + if( DEBUG_SETCLEAR ) { + final int glerr0 = gl.glGetError(); + if( GL.GL_NO_ERROR != glerr0 ) { + System.err.println("Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); + ExceptionUtils.dumpStack(System.err); + } + } + gl.glViewport(x, y, width, height); + gl.glClear(GL.GL_COLOR_BUFFER_BIT); } public final void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + setViewportAndClear(drawable, x, y, width, height); synchronized(listenersLock) { for (int i=0; i < listeners.size(); i++) { - reshape(listeners.get(i), drawable, x, y, width, height, 0==i /* setViewport */, true /* checkInit */); + final GLEventListener l = listeners.get(i); + // GLEventListener may need to be init, + // in case this one is added after the realization of the GLAutoDrawable + if( listenersToBeInit.remove(l) ) { + l.init(drawable); + } + l.reshape(drawable, x, y, width, height); } } } @@ -874,9 +877,8 @@ public class GLDrawableHelper { return false; } - GLRunnableTask rTask = null; + final GLRunnableTask rTask; final Object rTaskLock = new Object(); - Throwable throwable = null; synchronized(rTaskLock) { boolean deferredHere; synchronized(glRunnablesLock) { @@ -910,13 +912,13 @@ public class GLDrawableHelper { drawable.display(); } else if( wait ) { try { - rTaskLock.wait(); // free lock, allow execution of rTask + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); + throw new InterruptedRuntimeException(ie); } + final Throwable throwable = rTask.getThrowable(); if(null!=throwable) { throw new RuntimeException(throwable); } @@ -941,9 +943,8 @@ public class GLDrawableHelper { } final int count = newGLRunnables.size(); - GLRunnableTask rTask = null; + final GLRunnableTask rTask; final Object rTaskLock = new Object(); - Throwable throwable = null; synchronized(rTaskLock) { boolean deferredHere; synchronized(glRunnablesLock) { @@ -981,13 +982,13 @@ public class GLDrawableHelper { drawable.display(); } else if( wait ) { try { - rTaskLock.wait(); // free lock, allow execution of rTask + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); + throw new InterruptedRuntimeException(ie); } + final Throwable throwable = rTask.getThrowable(); if(null!=throwable) { throw new RuntimeException(throwable); } @@ -1082,6 +1083,21 @@ public class GLDrawableHelper { return exclusiveContextThread; } + /** + * Runs given {@code runnable} outside of a probable claimed exclusive thread, + * i.e. releases the exclusive thread, executes the runnable and reclaims it. + * @see #setExclusiveContextThread(Thread, GLContext) + * @since 2.3.2 + */ + public final void runOutsideOfExclusiveContextThread(final GLContext context, final Runnable runnable) { + final Thread t = setExclusiveContextThread(null, context); + try { + runnable.run(); + } finally { + setExclusiveContextThread(t, context); + } + } + private static final ThreadLocal<WeakReference<Runnable>> perThreadInitAction = new ThreadLocal<WeakReference<Runnable>>(); private static final Runnable getLastInitAction() { final WeakReference<Runnable> lastInitActionWR = perThreadInitAction.get(); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index 849a08623..98a0a0948 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -67,14 +67,6 @@ public abstract class GLDrawableImpl implements GLDrawable { this.requestedCapabilities = requestedCapabilities; } - /** - * Returns the DynamicLookupHelper - * @throws GLException if no DynamicLookupHelper is installed - */ - public final GLDynamicLookupHelper getGLDynamicLookupHelper() throws GLException { - return getFactoryImpl().getGLDynamicLookupHelper( getGLProfile().getImplName() ); - } - public final GLDrawableFactoryImpl getFactoryImpl() { return (GLDrawableFactoryImpl) getFactory(); } diff --git a/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java index 39de3200d..7c75b0615 100644 --- a/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/GLDynamicLibraryBundleInfo.java @@ -59,6 +59,16 @@ public abstract class GLDynamicLibraryBundleInfo implements DynamicLibraryBundle public boolean shallLookupGlobal() { return false; } @Override + public final boolean searchToolLibInSystemPath() { + return true; + } + + @Override + public final boolean searchToolLibSystemPathFirst() { + return true; + } + + @Override public final RunnableExecutor getLibLoaderExecutor() { return DynamicLibraryBundle.getDefaultRunnableExecutor(); } diff --git a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java index 1a6024bfa..cfe3df95d 100644 --- a/src/jogl/classes/jogamp/opengl/GLRunnableTask.java +++ b/src/jogl/classes/jogamp/opengl/GLRunnableTask.java @@ -29,6 +29,7 @@ package jogamp.opengl; import com.jogamp.opengl.GLRunnable; +import com.jogamp.common.ExceptionUtils; import com.jogamp.opengl.GLAutoDrawable; /** @@ -61,7 +62,7 @@ public class GLRunnableTask implements GLRunnable { } catch (final Throwable t) { runnableException = t; if(catchExceptions) { - runnableException.printStackTrace(); + ExceptionUtils.dumpThrowable("", runnableException); } else { throw new RuntimeException(runnableException); } @@ -75,7 +76,7 @@ public class GLRunnableTask implements GLRunnable { } catch (final Throwable t) { runnableException = t; if(catchExceptions) { - runnableException.printStackTrace(); + ExceptionUtils.dumpThrowable("", runnableException); } else { throw new RuntimeException(runnableException); } diff --git a/src/jogl/classes/jogamp/opengl/GLWorkerThread.java b/src/jogl/classes/jogamp/opengl/GLWorkerThread.java index c03cdea02..3d0adfc9c 100644 --- a/src/jogl/classes/jogamp/opengl/GLWorkerThread.java +++ b/src/jogl/classes/jogamp/opengl/GLWorkerThread.java @@ -43,6 +43,9 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.opengl.GLContext; /** Singleton thread upon which all OpenGL work is performed by @@ -78,15 +81,18 @@ public class GLWorkerThread { synchronized (GLWorkerThread.class) { if (!started) { lock = new Object(); - thread = new Thread(new WorkerRunnable(), - "JOGL-GLWorkerThread-"); + final WorkerRunnable worker = new WorkerRunnable(); + thread = new InterruptSource.Thread(null, worker, "JOGL-GLWorkerThread-"); thread.setDaemon(true); started = true; synchronized (lock) { thread.start(); try { - lock.wait(); + while(!worker.isRunning) { + lock.wait(); + } } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } } @@ -119,7 +125,7 @@ public class GLWorkerThread { // less cooperatively AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - Runtime.getRuntime().addShutdownHook(new Thread() { + Runtime.getRuntime().addShutdownHook(new InterruptSource.Thread() { public void run() { Object lockTemp = lock; if (lockTemp == null) { @@ -177,7 +183,9 @@ public class GLWorkerThread { work = runnable; lockTemp.notifyAll(); - lockTemp.wait(); + while( null != work ) { + lockTemp.wait(); + } if (exception != null) { final Throwable localException = exception; exception = null; @@ -222,10 +230,13 @@ public class GLWorkerThread { protected static String getThreadName() { return Thread.currentThread().getName(); } static class WorkerRunnable implements Runnable { + volatile boolean isRunning = false; + @Override public void run() { // Notify starting thread that we're ready synchronized (lock) { + isRunning = true; lock.notifyAll(); } @@ -238,6 +249,7 @@ public class GLWorkerThread { // Avoid race conditions with wanting to release contexts on this thread lock.wait(1000); } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } if (GLContext.getCurrent() != null) { @@ -269,8 +281,7 @@ public class GLWorkerThread { final Runnable curAsync = queue.remove(0); curAsync.run(); } catch (final Throwable t) { - System.err.println(getThreadName()+": Exception occurred on JOGL OpenGL worker thread:"); - t.printStackTrace(); + ExceptionUtils.dumpThrowable("suppressed", t); // Noncancelable } } @@ -285,6 +296,7 @@ public class GLWorkerThread { } } } + isRunning = false; } } } diff --git a/src/jogl/classes/jogamp/opengl/GLXExtensions.java b/src/jogl/classes/jogamp/opengl/GLXExtensions.java index 9325c6f68..db4757e4d 100644 --- a/src/jogl/classes/jogamp/opengl/GLXExtensions.java +++ b/src/jogl/classes/jogamp/opengl/GLXExtensions.java @@ -34,4 +34,10 @@ public class GLXExtensions { public static final String GLX_MESA_swap_control = "GLX_MESA_swap_control"; public static final String GLX_SGI_swap_control = "GLX_SGI_swap_control"; public static final String GLX_NV_swap_group = "GLX_NV_swap_group"; + + public static final String GLX_EXT_swap_control = "GLX_EXT_swap_control"; + public static final String GLX_EXT_swap_control_tear = "GLX_EXT_swap_control_tear"; + + public static final String WGL_EXT_swap_control = "WGL_EXT_swap_control"; + public static final String WGL_EXT_swap_control_tear = "WGL_EXT_swap_control_tear"; } diff --git a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java index 9b9093a87..0f6c1f875 100644 --- a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java +++ b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java @@ -28,14 +28,19 @@ package jogamp.opengl; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.AbstractGraphicsScreen; import com.jogamp.opengl.GLProfile; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; +import com.jogamp.common.util.SourcedInterruptedException; import com.jogamp.opengl.GLRendererQuirks; public class SharedResourceRunner implements Runnable { @@ -81,6 +86,29 @@ public class SharedResourceRunner implements Runnable { /** Called within synchronized block. */ Collection<Resource> mapValues(); } + public static abstract class AImplementation implements Implementation { + private final HashMap<String /* uniqueId */, SharedResourceRunner.Resource> sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); + /** Called within synchronized block. Use w/ care! */ + public Map<String /* uniqueId */, SharedResourceRunner.Resource> getSharedMap() { + return sharedMap; + } + @Override + public final void clear() { + sharedMap.clear(); + } + @Override + public final SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { + return sharedMap.put(device.getUniqueID(), resource); + } + @Override + public final SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { + return sharedMap.get(device.getUniqueID()); + } + @Override + public final Collection<SharedResourceRunner.Resource> mapValues() { + return sharedMap.values(); + } + } final HashSet<String> devicesTried = new HashSet<String>(); final Implementation impl; @@ -93,13 +121,13 @@ public class SharedResourceRunner implements Runnable { AbstractGraphicsDevice releaseDevice; private boolean getDeviceTried(final AbstractGraphicsDevice device) { // synchronized call - return devicesTried.contains(device.getConnection()); + return devicesTried.contains(device.getUniqueID()); } private void addDeviceTried(final AbstractGraphicsDevice device) { // synchronized call - devicesTried.add(device.getConnection()); + devicesTried.add(device.getUniqueID()); } private void removeDeviceTried(final AbstractGraphicsDevice device) { // synchronized call - devicesTried.remove(device.getConnection()); + devicesTried.remove(device.getUniqueID()); } public SharedResourceRunner(final Implementation impl) { @@ -141,13 +169,18 @@ public class SharedResourceRunner implements Runnable { System.err.println("SharedResourceRunner.start() - start new Thread - "+getThreadName()); } resetState(); - thread = new Thread(this, getThreadName()+"-SharedResourceRunner"); + thread = new InterruptSource.Thread(null, this, getThreadName()+"-SharedResourceRunner"); thread.setDaemon(true); // Allow JVM to exit, even if this one is running thread.start(); - while (!running) { - try { + try { + while (!running) { this.wait(); - } catch (final InterruptedException ex) { } + } + } catch (final InterruptedException ex) { + // Cleanup + shouldRelease = true; + this.notifyAll(); + throw new InterruptedRuntimeException(ex); } } } @@ -163,11 +196,12 @@ public class SharedResourceRunner implements Runnable { synchronized (this) { shouldRelease = true; this.notifyAll(); - - while (running) { - try { + try { + while (running) { this.wait(); - } catch (final InterruptedException ex) { } + } + } catch (final InterruptedException ex) { + throw new InterruptedRuntimeException(ex); } } } @@ -188,7 +222,11 @@ public class SharedResourceRunner implements Runnable { ExceptionUtils.dumpStack(System.err); } if ( impl.isDeviceSupported(device) ) { - doAndWait(device, null); + try { + doAndWait(device, null); + } catch (final InterruptedException ex) { + throw new InterruptedRuntimeException(ex); + } sr = impl.mapGet(device); } if (DEBUG) { @@ -211,7 +249,11 @@ public class SharedResourceRunner implements Runnable { if (DEBUG) { System.err.println("SharedResourceRunner.releaseShared() " + device + ": trying - "+getThreadName()); } - doAndWait(null, device); + try { + doAndWait(null, device); + } catch (final InterruptedException ex) { + throw new InterruptedRuntimeException(ex); + } if (DEBUG) { System.err.println("SharedResourceRunner.releaseShared() " + device + ": done - "+getThreadName()); } @@ -221,7 +263,7 @@ public class SharedResourceRunner implements Runnable { return sr; } - private final void doAndWait(final AbstractGraphicsDevice initDevice, final AbstractGraphicsDevice releaseDevice) { + private final void doAndWait(final AbstractGraphicsDevice initDevice, final AbstractGraphicsDevice releaseDevice) throws InterruptedException { synchronized (this) { // wait until thread becomes ready to init new device, // pass the device and release the sync @@ -229,26 +271,41 @@ public class SharedResourceRunner implements Runnable { if (DEBUG) { System.err.println("SharedResourceRunner.doAndWait() START init: " + initDevice + ", release: "+releaseDevice+" - "+threadName); } - while (!ready && running) { - try { + try { + while (!ready && running) { this.wait(); - } catch (final InterruptedException ex) { } - } - if (DEBUG) { - System.err.println("SharedResourceRunner.doAndWait() set command: " + initDevice + ", release: "+releaseDevice+" - "+threadName); - } - this.initDevice = initDevice; - this.releaseDevice = releaseDevice; - this.notifyAll(); + } + if (DEBUG) { + System.err.println("SharedResourceRunner.doAndWait() set command: " + initDevice + ", release: "+releaseDevice+" - "+threadName); + } + this.initDevice = initDevice; + this.releaseDevice = releaseDevice; + this.notifyAll(); - // wait until thread has init/released the device - while ( running && ( !ready || null != this.initDevice || null != this.releaseDevice ) ) { - try { + // wait until thread has init/released the device + while ( running && ( !ready || null != this.initDevice || null != this.releaseDevice ) ) { this.wait(); - } catch (final InterruptedException ex) { } + } + } catch (final InterruptedException ex) { + final InterruptedException ex2 = SourcedInterruptedException.wrap(ex); + if (DEBUG) { + System.err.println("SharedResourceRunner.doAndWait() INTERRUPT init: " + initDevice + ", release: "+releaseDevice+" - "+threadName); + ExceptionUtils.dumpThrowable("", ex2); + } + // Cleanup initDevice due to exception! + final AbstractGraphicsDevice _initDevice = this.initDevice; + if( null != _initDevice ) { + if (DEBUG) { + System.err.println("SharedResourceRunner.doAndWait() Cleanup init: " + _initDevice + " -> release: "+this.releaseDevice+" - "+threadName); + } + this.releaseDevice = _initDevice; + this.initDevice = null; + this.notifyAll(); + } + throw ex2; } if (DEBUG) { - System.err.println("SharedResourceRunner.initializeAndWait END init: " + initDevice + ", release: "+releaseDevice+" - "+threadName); + System.err.println("SharedResourceRunner.doAndWait() END init: " + initDevice + ", release: "+releaseDevice+" - "+threadName); } } // done @@ -267,19 +324,18 @@ public class SharedResourceRunner implements Runnable { while (!shouldRelease) { try { - // wait for stop or init + // wait until call-thread issues stop or init/released a device ready = true; if (DEBUG) { System.err.println("SharedResourceRunner.run(): READY - " + threadName); } notifyAll(); - this.wait(); + while ( !shouldRelease && null == initDevice && null == releaseDevice ) { + this.wait(); + } } catch (final InterruptedException ex) { shouldRelease = true; - if(DEBUG) { - System.err.println("SharedResourceRunner.run(): INTERRUPTED - "+threadName); - ex.printStackTrace(); - } + ExceptionUtils.dumpThrowable("handled", SourcedInterruptedException.wrap(ex)); // cancelable } ready = false; @@ -296,7 +352,7 @@ public class SharedResourceRunner implements Runnable { try { sr = impl.createSharedResource(initDevice); } catch (final Exception e) { - e.printStackTrace(); + ExceptionUtils.dumpThrowable("handled", e); } if (null != sr) { impl.mapPut(initDevice, sr); @@ -310,9 +366,10 @@ public class SharedResourceRunner implements Runnable { if (null != sr) { try { impl.releaseSharedResource(sr); - impl.mapPut(releaseDevice, null); } catch (final Exception e) { - e.printStackTrace(); + ExceptionUtils.dumpThrowable("handled", e); + } finally { + impl.mapPut(releaseDevice, null); } } } @@ -345,8 +402,7 @@ public class SharedResourceRunner implements Runnable { try { impl.releaseSharedResource(iter.next()); } catch (final Throwable t) { - System.err.println("Caught exception on thread "+getThreadName()); - t.printStackTrace(); + ExceptionUtils.dumpThrowable("", t); } } impl.clear(); diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java index da81922a4..09d2dfda0 100644 --- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java +++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java @@ -33,7 +33,6 @@ import java.util.List; import com.jogamp.opengl.GL; import com.jogamp.opengl.GLES2; import com.jogamp.opengl.GLException; - import com.jogamp.common.os.AndroidVersion; import com.jogamp.common.os.Platform; import com.jogamp.opengl.util.TimeFrameI; @@ -364,7 +363,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { } @Override - protected final int getNextTextureImpl(final GL gl, final TextureFrame nextFrame) { + protected final int getNextTextureImpl(final GL gl, final TextureFrame nextFrame) throws InterruptedException { int pts = TimeFrameI.INVALID_PTS; if(null != mp || null != cam) { final SurfaceTextureFrame sTexFrame = null != nextFrame ? (SurfaceTextureFrame) nextFrame : singleSTexFrame; @@ -398,12 +397,8 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { boolean update = updateSurface; if( !update ) { synchronized(updateSurfaceLock) { - if(!updateSurface) { // volatile OK. - try { - updateSurfaceLock.wait(); - } catch (final InterruptedException e) { - e.printStackTrace(); - } + while(!updateSurface) { // volatile OK. + updateSurfaceLock.wait(); // propagates InterruptedException } update = updateSurface; updateSurface = false; diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index b6a05aeeb..28448d537 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -49,9 +49,9 @@ import com.jogamp.opengl.GLProfile; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.egl.EGLExtImpl; import jogamp.opengl.egl.EGLExtProcAddressTable; -import jogamp.opengl.windows.wgl.WindowsWGLContext; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; @@ -168,19 +168,17 @@ public class EGLContext extends GLContextImpl { final long eglConfig = config.getNativeConfig(); final EGLDrawableFactory factory = (EGLDrawableFactory) drawable.getFactoryImpl(); - final boolean hasOpenGLAPISupport = factory.hasOpenGLAPISupport(); + final boolean hasFullOpenGLAPISupport = factory.hasOpenGLDesktopSupport(); final boolean useKHRCreateContext = factory.hasDefaultDeviceKHRCreateContext(); - final boolean allowOpenGLAPI = hasOpenGLAPISupport && useKHRCreateContext; - final boolean ctDesktopGL = 0 == ( GLContext.CTX_PROFILE_ES & ctp ); + final boolean ctDesktopGL = 0 == ( CTX_PROFILE_ES & ctp ); final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; final boolean ctFwdCompat = 0 != ( CTX_OPTION_FORWARD & ctp ) ; final boolean ctDebug = 0 != ( CTX_OPTION_DEBUG & ctp ) ; if(DEBUG) { System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: Start "+getGLVersion(reqMajor, reqMinor, ctp, "@creation") - + ", hasOpenGLAPISupport "+hasOpenGLAPISupport + ", useKHRCreateContext "+useKHRCreateContext - + ", allowOpenGLAPI "+allowOpenGLAPI + + ", OpenGL API Support "+hasFullOpenGLAPISupport + ", device "+device); } if ( 0 == eglDisplay ) { @@ -203,8 +201,7 @@ public class EGLContext extends GLContextImpl { * hence it must be switched before makeCurrent w/ different APIs, see: * eglWaitClient(); */ - if( ctDesktopGL && !allowOpenGLAPI ) { - // if( ctDesktopGL && !hasOpenGLAPISupport ) { + if( ctDesktopGL && !hasFullOpenGLAPISupport ) { if(DEBUG) { System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: DesktopGL not avail "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")); } @@ -212,7 +209,7 @@ public class EGLContext extends GLContextImpl { } try { - if( allowOpenGLAPI && device.getEGLVersion().compareTo(Version1_2) >= 0 ) { + if( hasFullOpenGLAPISupport && device.getEGLVersion().compareTo(Version1_2) >= 0 ) { EGL.eglWaitClient(); // EGL >= 1.2 } if( !EGL.eglBindAPI( ctDesktopGL ? EGL.EGL_OPENGL_API : EGL.EGL_OPENGL_ES_API) ) { @@ -238,11 +235,11 @@ public class EGLContext extends GLContextImpl { int index = ctx_attribs_idx_major + 2; - /** if( ctDesktopGL && reqMinor >= 0 ) { // FIXME: No minor version probing for ES currently! + if( reqMinor >= 0 ) { attribs.put(index + 0, EGLExt.EGL_CONTEXT_MINOR_VERSION_KHR); attribs.put(index + 1, reqMinor); index += 2; - } */ + } if( ctDesktopGL && ( useMajor > 3 || useMajor == 3 && reqMinor >= 2 ) ) { attribs.put(index + 0, EGLExt.EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); @@ -364,14 +361,17 @@ public class EGLContext extends GLContextImpl { } @Override - protected final void updateGLXProcAddressTable() { + protected final void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh) { + if( null == dlh ) { + throw new GLException("No GLDynamicLookupHelper for "+this); + } final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "EGL-"+adevice.getUniqueID(); + // final String key = contextFQN; if (DEBUG) { System.err.println(getThreadName() + ": Initializing EGLextension address table: "+key); } - ProcAddressTable table = null; synchronized(mappedContextTypeObjectLock) { table = mappedGLXProcAddress.get( key ); @@ -386,7 +386,7 @@ public class EGLContext extends GLContextImpl { } } else { eglExtProcAddressTable = new EGLExtProcAddressTable(new GLProcAddressResolver()); - resetProcAddressTable(eglExtProcAddressTable); + resetProcAddressTable(eglExtProcAddressTable, dlh); synchronized(mappedContextTypeObjectLock) { mappedGLXProcAddress.put(key, eglExtProcAddressTable); if(DEBUG) { @@ -432,11 +432,21 @@ public class EGLContext extends GLContextImpl { } @Override - protected boolean setSwapIntervalImpl(final int interval) { - if( hasRendererQuirk(GLRendererQuirks.NoSetSwapInterval) ) { - return false; + protected final Integer setSwapIntervalImpl2(final int interval) { + if( !drawable.getChosenGLCapabilities().isOnscreen() || + hasRendererQuirk(GLRendererQuirks.NoSetSwapInterval) ) { + return null; + } + final int useInterval; + if( 0 > interval ) { + useInterval = Math.abs(interval); + } else { + useInterval = interval; } - return EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), interval); + if( EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), useInterval) ) { + return Integer.valueOf(useInterval); + } + return null; } static long eglGetProcAddress(final long eglGetProcAddressHandle, final String procname) @@ -453,52 +463,32 @@ public class EGLContext extends GLContextImpl { // Accessible .. // - /* pp */ void mapCurrentAvailableGLESVersion(final AbstractGraphicsDevice device) { - mapStaticGLESVersion(device, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); + /* pp */ static final boolean isGLES1(final int majorVersion, final int ctxOptions) { + return 0 != ( ctxOptions & GLContext.CTX_PROFILE_ES ) && majorVersion == 1 ; } - /* pp */ int getContextOptions() { return ctxOptions; } - /* pp */ static void mapStaticGLESVersion(final AbstractGraphicsDevice device, final GLCapabilitiesImmutable caps) { - final GLProfile glp = caps.getGLProfile(); - final int[] reqMajorCTP = new int[2]; - GLContext.getRequestMajorAndCompat(glp, reqMajorCTP); - if( glp.isGLES() ) { - if( reqMajorCTP[0] >= 3 ) { - reqMajorCTP[1] |= GLContext.CTX_IMPL_ES3_COMPAT | GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_FBO ; - } else if( reqMajorCTP[0] >= 2 ) { - reqMajorCTP[1] |= GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_FBO ; - } - } - if( !caps.getHardwareAccelerated() ) { - reqMajorCTP[1] |= GLContext.CTX_IMPL_ACCEL_SOFT; + /* pp */ static final boolean isGLES2ES3(final int majorVersion, final int ctxOptions) { + if( 0 != ( ctxOptions & CTX_PROFILE_ES ) ) { + return 2 == majorVersion || 3 == majorVersion; + } else { + return false; } - mapStaticGLESVersion(device, reqMajorCTP[0], 0, reqMajorCTP[1]); } - /* pp */ static void mapStaticGLESVersion(final AbstractGraphicsDevice device, final int major, final int minor, final int ctp) { - if( 0 != ( ctp & GLContext.CTX_PROFILE_ES) ) { - // ES1, ES2, ES3, .. - mapStaticGLESVersion(device, major /* reqMajor */, major, minor, ctp); - if( 3 == major ) { - // map ES2 -> ES3 - mapStaticGLESVersion(device, 2 /* reqMajor */, major, minor, ctp); - } - } + /* pp */ static final boolean isGLDesktop(final int ctxOptions) { + return 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); } - private static void mapStaticGLESVersion(final AbstractGraphicsDevice device, final int reqMajor, final int major, final int minor, final int ctp) { - GLContext.mapAvailableGLVersion(device, reqMajor, GLContext.CTX_PROFILE_ES, major, minor, ctp); - if(! ( device instanceof EGLGraphicsDevice ) ) { - final EGLGraphicsDevice eglDevice = new EGLGraphicsDevice(device.getHandle(), EGL.EGL_NO_DISPLAY, device.getConnection(), device.getUnitID(), null); - GLContext.mapAvailableGLVersion(eglDevice, reqMajor, GLContext.CTX_PROFILE_ES, major, minor, ctp); - } + protected static StringBuilder getGLProfile(final StringBuilder sb, final int ctp) { + return GLContext.getGLProfile(sb, ctp); } - protected static String getGLVersion(final int major, final int minor, final int ctp, final String gl_version) { - return GLContext.getGLVersion(major, minor, ctp, gl_version); + /* pp */ int getContextOptions() { return ctxOptions; } + protected static void remapAvailableGLVersions(final AbstractGraphicsDevice fromDevice, final AbstractGraphicsDevice toDevice) { + GLContextImpl.remapAvailableGLVersions(fromDevice, toDevice); } - - protected static boolean getAvailableGLVersionsSet(final AbstractGraphicsDevice device) { - return GLContext.getAvailableGLVersionsSet(device); + protected static synchronized void setMappedGLVersionListener(final MappedGLVersionListener mvl) { + GLContextImpl.setMappedGLVersionListener(mvl); } - protected static void setAvailableGLVersionsSet(final AbstractGraphicsDevice device, final boolean set) { - GLContext.setAvailableGLVersionsSet(device, set); + + protected static String getGLVersion(final int major, final int minor, final int ctp, final String gl_version) { + return GLContext.getGLVersion(major, minor, ctp, gl_version); } protected static String toHexString(final int hex) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java index 3d2d03403..fcd4f54eb 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java @@ -80,10 +80,17 @@ public class EGLDisplayUtil { static EGLDisplayRef getOrCreateOpened(final long eglDisplay, final IntBuffer major, final IntBuffer minor) { final EGLDisplayRef o = (EGLDisplayRef) openEGLDisplays.get(eglDisplay); if( null == o ) { - if( EGL.eglInitialize(eglDisplay, major, minor) ) { + final boolean ok = EGL.eglInitialize(eglDisplay, major, minor); + if( DEBUG ) { + System.err.println("EGLDisplayUtil.EGL.eglInitialize 0x"+Long.toHexString(eglDisplay)+" -> "+ok); + } + if( ok ) { final EGLDisplayRef n = new EGLDisplayRef(eglDisplay); openEGLDisplays.put(eglDisplay, n); n.initRefCount++; + if( DEBUG ) { + System.err.println("EGLDisplayUtil.EGL.eglInitialize "+n); + } if( null == singletonEGLDisplay ) { singletonEGLDisplay = n; } @@ -113,7 +120,12 @@ public class EGLDisplayUtil { if( 0 < o.initRefCount ) { // no negative refCount o.initRefCount--; if( 0 == o.initRefCount ) { - res[0] = EGL.eglTerminate(eglDisplay); + final boolean ok = EGL.eglTerminate(eglDisplay); + if( DEBUG ) { + System.err.println("EGLDisplayUtil.EGL.eglTerminate 0x"+Long.toHexString(eglDisplay)+" -> "+ok); + System.err.println("EGLDisplayUtil.EGL.eglTerminate "+o); + } + res[0] = ok; if( o == singletonEGLDisplay ) { singletonEGLDisplay = null; } @@ -340,6 +352,22 @@ public class EGLDisplayUtil { * <p> * Using the default {@link ToolkitLock}, via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. * </p> + * @param adevice + * @return an uninitialized {@link EGLGraphicsDevice} + */ + public static EGLGraphicsDevice eglCreateEGLGraphicsDevice(final AbstractGraphicsDevice aDevice) { + return new EGLGraphicsDevice(aDevice, EGL.EGL_NO_DISPLAY, eglLifecycleCallback); + } + + /** + * Returns an uninitialized {@link EGLGraphicsDevice}. User needs to issue {@link EGLGraphicsDevice#open()} before usage. + * <p> + * Using {@link #eglGetDisplayAndInitialize(long[])} for the {@link EGLGraphicsDevice#open()} implementation + * and {@link #eglTerminate(long)} for {@link EGLGraphicsDevice#close()}. + * </p> + * <p> + * Using the default {@link ToolkitLock}, via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. + * </p> * @param surface * @return an uninitialized EGLGraphicsDevice */ diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index e63a63634..ef3c96aeb 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -36,6 +36,7 @@ package jogamp.opengl.egl; +import com.jogamp.common.ExceptionUtils; import com.jogamp.nativewindow.ProxySurface; import com.jogamp.opengl.GLContext; import com.jogamp.opengl.GLException; @@ -82,7 +83,10 @@ public class EGLDrawable extends GLDrawableImpl { final EGLSurface eglSurf = (EGLSurface) surface; final long eglSurfHandle = eglSurf.getSurfaceHandle(); if(DEBUG) { - System.err.println(getThreadName() + ": destroyHandle of "+eglSurf); + System.err.println(getThreadName() + ": EGLDrawable: destroyHandle of "+toHexString(eglSurfHandle)); + ProxySurfaceImpl.dumpHierarchy(System.err, eglSurf); + System.err.println(getThreadName() + ": EGLSurface : "+eglSurf); + ExceptionUtils.dumpStack(System.err); } if( !eglSurf.containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS ) && EGL.EGL_NO_SURFACE == eglSurfHandle ) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 4fecafdfc..fed02f34e 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -38,10 +38,9 @@ package jogamp.opengl.egl; import java.nio.IntBuffer; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import com.jogamp.nativewindow.AbstractGraphicsConfiguration; @@ -67,6 +66,7 @@ import com.jogamp.opengl.GLProfile; import jogamp.common.os.PlatformPropsImpl; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLContextImpl.MappedGLVersion; import jogamp.opengl.GLDrawableFactoryImpl; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLDynamicLookupHelper; @@ -78,7 +78,6 @@ import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.os.DynamicLookupHelper; import com.jogamp.common.os.Platform; -import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.common.util.VersionNumber; import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; @@ -90,17 +89,20 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG; // allow package access private static final boolean DEBUG_SHAREDCTX = DEBUG || GLContext.DEBUG; - /* package */ static final boolean QUERY_EGL_ES_NATIVE_TK; - static { Debug.initSingleton(); - QUERY_EGL_ES_NATIVE_TK = PropertyAccess.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true); } private static boolean eglDynamicLookupHelperInit = false; private static GLDynamicLookupHelper eglES1DynamicLookupHelper = null; private static GLDynamicLookupHelper eglES2DynamicLookupHelper = null; private static GLDynamicLookupHelper eglGLnDynamicLookupHelper = null; + private static boolean isANGLE = false; + private static boolean hasX11 = false; + private static String defaultConnection = null; + private static EGLGraphicsDevice defaultDevice = null; + private static EGLFeatures defaultDeviceEGLFeatures = null; + private static SharedResource defaultSharedResource = null; private static final boolean isANGLE(final GLDynamicLookupHelper dl) { if(Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE) { @@ -128,7 +130,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { public EGLFeatures(final EGLGraphicsDevice device) { final long eglDisplay = device.getHandle(); vendor = EGL.eglQueryString(eglDisplay, EGL.EGL_VENDOR); - if(DEBUG) { + if(DEBUG_SHAREDCTX) { System.err.println("EGLFeatures on device "+device+", vendor "+vendor); } version = device.getEGLVersion(); @@ -139,13 +141,13 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final String eglClientAPIStr = EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS); if( hasEGL_1_4 ) { final String[] eglClientAPIs = eglClientAPIStr.split("\\s"); - for(int i=eglClientAPIs.length-1; i>=0; i--) { + for(int i=eglClientAPIs.length-1; !_hasGLAPI && i>=0; i--) { _hasGLAPI = eglClientAPIs[i].equals("OpenGL"); } } hasGLAPI = _hasGLAPI; - if(DEBUG) { - System.err.println(" Client APIs: "+eglClientAPIStr+"; has EGL 1.4 "+hasEGL_1_4+" -> has OpenGL "+hasGLAPI); + if(DEBUG_SHAREDCTX) { + System.err.println(" Client APIs: '"+eglClientAPIStr+"'; has EGL 1.4 "+hasEGL_1_4+" -> has OpenGL "+hasGLAPI); } } { @@ -163,7 +165,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } hasKHRSurfaceless = extensions.contains("EGL_KHR_surfaceless_context"); } - if(DEBUG) { + if(DEBUG_SHAREDCTX) { System.err.println(" Extensions: "+extensions); System.err.println(" KHR_create_context: "+hasKHRCreateContext); System.err.println(" KHR_surfaceless_context: "+hasKHRSurfaceless); @@ -193,12 +195,16 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { eglDynamicLookupHelperInit = true; // Check for other underlying stuff .. - if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true)) { + final String nwt = NativeWindowFactory.getNativeWindowType(true); + if(NativeWindowFactory.TYPE_X11 == nwt) { hasX11 = true; try { ReflectionUtil.createInstance("jogamp.opengl.x11.glx.X11GLXGraphicsConfigurationFactory", EGLDrawableFactory.class.getClassLoader()); } catch (final Exception jre) { /* n/a .. */ } + } else { + hasX11 = false; } + defaultConnection = NativeWindowFactory.getDefaultDisplayConnection(nwt); /** * FIXME: Probably need to move EGL from a static model @@ -337,14 +343,14 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { // The act of constructing them causes them to be registered EGLGraphicsConfigurationFactory.registerFactory(); - sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); - - // FIXME: defaultDevice.open() triggers eglInitialize(..) which crashed on Windows w/ Chrome/ANGLE, FF/ANGLE! - defaultDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + // Note: defaultDevice.open() triggers eglInitialize(..) which crashed on Windows w/ Chrome/ANGLE, FF/ANGLE! + // Hence opening will happen later, eventually + defaultDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, defaultConnection, AbstractGraphicsDevice.DEFAULT_UNIT); // Init shared resources off thread // Will be released via ShutdownHook - sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); + sharedResourceImplementation = new SharedResourceImplementation(); + sharedResourceRunner = new SharedResourceRunner(sharedResourceImplementation); sharedResourceRunner.start(); } } @@ -353,7 +359,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected final boolean isComplete() { - return null != sharedMap; // null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper; + return null != sharedResourceImplementation; // null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper || ..; } @@ -366,9 +372,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { sharedResourceRunner.stop(); sharedResourceRunner = null; } - if(null != sharedMap) { - sharedMap.clear(); - sharedMap = null; + if(null != sharedResourceImplementation) { + sharedResourceImplementation.clear(); + sharedResourceImplementation = null; } if(null != defaultDevice) { @@ -395,57 +401,63 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } private void dumpMap() { - synchronized(sharedMap) { - System.err.println("EGLDrawableFactory.map "+sharedMap.size()); + synchronized(sharedResourceImplementation) { + final Map<String /* uniqueId */, SharedResourceRunner.Resource> sharedMap = sharedResourceImplementation.getSharedMap(); + System.err.println("EGLDrawableFactory.MapGLVersion.map "+sharedMap.size()); int i=0; final Set<String> keys = sharedMap.keySet(); for(final Iterator<String> keyI = keys.iterator(); keyI.hasNext(); i++) { final String key = keyI.next(); final SharedResource sr = (SharedResource) sharedMap.get(key); - System.err.println("EGLDrawableFactory.map["+i+"] "+key+" -> "+sr.getDevice()+", avail "+sr.isAvailable+ - "gln [quirks "+sr.rendererQuirksGLn+", ctp "+EGLContext.getGLVersion(3, 0, sr.ctpGLn, null)+"], "+ - "es1 [quirks "+sr.rendererQuirksES1+", ctp "+EGLContext.getGLVersion(1, 0, sr.ctpES1, null)+"], "+ - "es2/3 [quirks "+sr.rendererQuirksES3ES2+", ctp "+EGLContext.getGLVersion(2, 0, sr.ctpES3ES2, null)+"]"); + System.err.println("EGLDrawableFactory.MapGLVersion.map["+i+"] "+key+" -> "+sr.getDevice()+", avail "+sr.isAvailable+", "+ + "es1 [avail "+sr.isAvailableES1+", quirks "+sr.rendererQuirksES1+", ctp "+EGLContext.getGLVersion(1, 0, sr.ctpES1, null)+"], "+ + "es2 [avail "+sr.isAvailableES2+", quirks "+sr.rendererQuirksES2+", ctp "+EGLContext.getGLVersion(2, 0, sr.ctpES2, null)+"], "+ + "es3 [avail "+sr.isAvailableES3+", quirks "+sr.rendererQuirksES3+", ctp "+EGLContext.getGLVersion(2, 0, sr.ctpES3, null)+"], "+ + "gln [avail "+sr.isAvailableGLn+", quirks "+sr.rendererQuirksGLn+", ctp "+EGLContext.getGLVersion(3, 0, sr.ctpGLn, null)+"]"); } ; } } - private boolean isANGLE = false; - private boolean hasX11 = false; - private EGLGraphicsDevice defaultDevice = null; - private EGLFeatures defaultDeviceEGLFeatures; + private SharedResourceImplementation sharedResourceImplementation; private SharedResourceRunner sharedResourceRunner; - private HashMap<String /* uniqueKey */, SharedResourceRunner.Resource> sharedMap; static class SharedResource implements SharedResourceRunner.Resource { private EGLGraphicsDevice device; - // private final EGLContext contextES1; - // private final EGLContext contextES2; - // private final EGLContext contextES3; final boolean isAvailable; - final GLRendererQuirks rendererQuirksGLn; + final boolean isAvailableES1; + final boolean isAvailableES2; + final boolean isAvailableES3; + final boolean isAvailableGLn; final GLRendererQuirks rendererQuirksES1; - final GLRendererQuirks rendererQuirksES3ES2; - final int ctpGLn; + final GLRendererQuirks rendererQuirksES2; + final GLRendererQuirks rendererQuirksES3; + final GLRendererQuirks rendererQuirksGLn; final int ctpES1; - final int ctpES3ES2; + final int ctpES2; + final int ctpES3; + final int ctpGLn; - SharedResource(final EGLGraphicsDevice dev, final boolean isAvailable, - final GLRendererQuirks rendererQuirksGLn, final int ctpGLn, - final GLRendererQuirks rendererQuirksES1, final int ctpES1, - final GLRendererQuirks rendererQuirksES3ES2, final int ctpES3ES2) { + SharedResource(final EGLGraphicsDevice dev, + final boolean isAvailableES1, final GLRendererQuirks rendererQuirksES1, final int ctpES1, + final boolean isAvailableES2, final GLRendererQuirks rendererQuirksES2, final int ctpES2, + final boolean isAvailableES3, final GLRendererQuirks rendererQuirksES3, final int ctpES3, + final boolean isAvailableGLn, final GLRendererQuirks rendererQuirksGLn, final int ctpGLn) { this.device = dev; - this.isAvailable = isAvailable; - - this.rendererQuirksGLn = rendererQuirksGLn; - this.ctpGLn = ctpGLn; + this.isAvailable = isAvailableES1 || isAvailableES2 || isAvailableES3 || isAvailableGLn; + this.isAvailableES1 = isAvailableES1; this.rendererQuirksES1 = rendererQuirksES1; this.ctpES1 = ctpES1; - - this.rendererQuirksES3ES2 = rendererQuirksES3ES2; - this.ctpES3ES2 = ctpES3ES2; + this.isAvailableES2 = isAvailableES2; + this.rendererQuirksES2 = rendererQuirksES2; + this.ctpES2 = ctpES2; + this.isAvailableES3 = isAvailableES3; + this.rendererQuirksES3 = rendererQuirksES3; + this.ctpES3 = ctpES3; + this.isAvailableGLn = isAvailableGLn; + this.rendererQuirksGLn = rendererQuirksGLn; + this.ctpGLn = ctpGLn; } @Override @@ -470,8 +482,10 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { @Override public GLRendererQuirks getRendererQuirks(final GLProfile glp) { if( null == glp ) { - if( null != rendererQuirksES3ES2 ) { - return rendererQuirksES3ES2; + if( null != rendererQuirksES3 ) { + return rendererQuirksES3; + } else if( null != rendererQuirksES2 ) { + return rendererQuirksES2; } else if( null != rendererQuirksES1 ) { return rendererQuirksES1; } else { @@ -481,33 +495,18 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return rendererQuirksGLn; } else if( glp.isGLES1() ) { return rendererQuirksES1; - } else { - return rendererQuirksES3ES2; + } else if( glp.isGLES2() ) { + return rendererQuirksES2; + } else /* if( glp.isGLES3() ) */ { + return rendererQuirksES3; } } } - class SharedResourceImplementation implements SharedResourceRunner.Implementation { - @Override - public void clear() { - sharedMap.clear(); - } - @Override - public SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { - return sharedMap.put(device.getConnection(), resource); - } - @Override - public SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { - return sharedMap.get(device.getConnection()); - } - @Override - public Collection<SharedResourceRunner.Resource> mapValues() { - return sharedMap.values(); - } - + class SharedResourceImplementation extends SharedResourceRunner.AImplementation { @Override public boolean isDeviceSupported(final AbstractGraphicsDevice device) { - return null != sharedMap; // null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper + return null != sharedResourceImplementation; // null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper || .. } @Override @@ -523,78 +522,128 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } private SharedResource createEGLSharedResourceImpl(final AbstractGraphicsDevice adevice) { - final GLRendererQuirks[] rendererQuirksES1 = new GLRendererQuirks[] { null }; - final GLRendererQuirks[] rendererQuirksES3ES2 = new GLRendererQuirks[] { null }; - final GLRendererQuirks[] rendererQuirksGLn = new GLRendererQuirks[] { null }; - final int[] ctpES1 = new int[] { EGLContext.CTX_PROFILE_ES }; - final int[] ctpES3ES2 = new int[] { EGLContext.CTX_PROFILE_ES }; - final int[] ctpGLn = new int[] { EGLContext.CTX_PROFILE_CORE }; - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.createShared(): device "+adevice); + System.err.println("EGLDrawableFactory.MapGLVersions: device "+adevice); } - boolean madeCurrentES1 = false; - boolean madeCurrentES2 = false; - boolean madeCurrentES3 = false; - boolean madeCurrentGLn = false; - - if( null != eglGLnDynamicLookupHelper ) { - // OpenGL 3.1 core -> GL3, will utilize normal desktop profile mapping - final int[] major = { 3 }; - final int[] minor = { 1 }; // FIXME: No minor version probing for ES currently! - madeCurrentGLn = mapAvailableEGLESConfig(adevice, major, minor, - ctpGLn, rendererQuirksGLn) && 0 != major[0]; + final boolean initDefaultDevice; + if( 0 == defaultDevice.getHandle() ) { // Note: GLProfile always triggers EGL device initialization first! + initDefaultDevice = true; + defaultDevice.open(); + defaultDeviceEGLFeatures = new EGLFeatures(defaultDevice); + if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory.MapGLVersions: defaultDevice "+defaultDevice); + System.err.println("EGLDrawableFactory.MapGLVersions: defaultDevice EGLFeatures "+defaultDeviceEGLFeatures); + } + // Probe for GLRendererQuirks.SingletonEGLDisplayOnly + final boolean singletonEGLDisplayOnlyVendor, singletonEGLDisplayOnlyProbe; + if( defaultDeviceEGLFeatures.vendor.contains("NVIDIA") ) { // OpenGL ES 3.1 NVIDIA 355.06 unstable + singletonEGLDisplayOnlyVendor=true; + singletonEGLDisplayOnlyProbe=false; + } else { + singletonEGLDisplayOnlyVendor=false; + final long secondEGLDisplay = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY); + singletonEGLDisplayOnlyProbe = EGL.EGL_NO_DISPLAY == secondEGLDisplay; + } + if( singletonEGLDisplayOnlyVendor || singletonEGLDisplayOnlyProbe ) { + final int quirk = GLRendererQuirks.SingletonEGLDisplayOnly; + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + EGLDisplayUtil.setSingletonEGLDisplayOnly(true); + if ( DEBUG_SHAREDCTX ) { + if( singletonEGLDisplayOnlyVendor ) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Vendor: "+defaultDeviceEGLFeatures); + } else if( singletonEGLDisplayOnlyProbe ) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Second eglGetDisplay(EGL_DEFAULT_DISPLAY) failed"); + } + } + } } else { - madeCurrentGLn = false; + initDefaultDevice = false; + if( null == defaultSharedResource ) { + throw new InternalError("XXX: defaultDevice "+defaultDevice+", adevice "+adevice); + } } - EGLContext.setAvailableGLVersionsSet(adevice, true); - if( null != eglES1DynamicLookupHelper ) { - final int[] major = { 1 }; - final int[] minor = { 0 }; - madeCurrentES1 = mapAvailableEGLESConfig(adevice, major, minor, - ctpES1, rendererQuirksES1) && 1 == major[0]; - } else { - madeCurrentES1 = false; - } - if( null != eglES2DynamicLookupHelper ) { - // ES3 Query - final int[] major = { 3 }; - final int[] minor = { 0 }; - madeCurrentES3 = mapAvailableEGLESConfig(adevice, major, minor, - ctpES3ES2, rendererQuirksES3ES2) && 3 == major[0]; - if( !madeCurrentES3 ) { - // ES2 Query, may result in ES3 - major[0] = 2; - if( mapAvailableEGLESConfig(adevice, major, minor, - ctpES3ES2, rendererQuirksES3ES2) ) - { - switch( major[0] ) { - case 2: madeCurrentES2 = true; break; - case 3: madeCurrentES3 = true; break; - default: throw new InternalError("XXXX Got "+major[0]); + final boolean[] mappedToDefaultDevice = { false }; + final GLRendererQuirks[] rendererQuirksES1 = new GLRendererQuirks[] { null }; + final GLRendererQuirks[] rendererQuirksES2 = new GLRendererQuirks[] { null }; + final GLRendererQuirks[] rendererQuirksES3 = new GLRendererQuirks[] { null }; + final GLRendererQuirks[] rendererQuirksGLn = new GLRendererQuirks[] { null }; + final int[] ctpES1 = new int[] { 0 }; + final int[] ctpES2 = new int[] { 0 }; + final int[] ctpES3 = new int[] { 0 }; + final int[] ctpGLn = new int[] { 0 }; + final boolean[] madeCurrentES1 = { false }; + final boolean[] madeCurrentES2 = { false }; + final boolean[] madeCurrentES3 = { false }; + final boolean[] madeCurrentGLn = { false }; + + final GLContextImpl.MappedGLVersionListener mvl = new GLContextImpl.MappedGLVersionListener() { + @Override + public void glVersionMapped(final MappedGLVersion e) { + if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory.MapGLVersions: Mapped: "+e); + } + if ( EGLContext.isGLES2ES3(e.ctxVersion.getMajor(), e.ctxOptions) ) { + if( e.ctxVersion.getMajor() == 3 ) { + madeCurrentES3[0] = true; + rendererQuirksES3[0] = e.quirks; + ctpES3[0] = e.ctxOptions; } + madeCurrentES2[0] = true; + rendererQuirksES2[0] = e.quirks; + ctpES2[0] = e.ctxOptions; + } else if ( EGLContext.isGLES1(e.ctxVersion.getMajor(), e.ctxOptions) ) { + madeCurrentES1[0] = true; + rendererQuirksES1[0] = e.quirks; + ctpES1[0] = e.ctxOptions; + } else if( EGLContext.isGLDesktop(e.ctxOptions) ) { + madeCurrentGLn[0] = true; + rendererQuirksGLn[0] = e.quirks; + ctpGLn[0] = e.ctxOptions; } } + }; + final SharedResource sr; + final EGLGraphicsDevice[] eglDevice = { null }; + final boolean mapSuccess; + EGLContext.setMappedGLVersionListener(mvl); + try { + // Query triggers profile mapping! + mapSuccess = mapAvailableEGLESConfig(adevice, mappedToDefaultDevice, eglDevice); + } finally { + EGLContext.setMappedGLVersionListener(null); } - if( hasX11 ) { - handleDontCloseX11DisplayQuirk(rendererQuirksES1[0]); - handleDontCloseX11DisplayQuirk(rendererQuirksES3ES2[0]); + if( mappedToDefaultDevice[0] ) { + EGLContext.remapAvailableGLVersions(defaultDevice, adevice); + sr = defaultSharedResource; + } else { + if( hasX11 ) { + handleDontCloseX11DisplayQuirk(rendererQuirksES1[0]); + handleDontCloseX11DisplayQuirk(rendererQuirksGLn[0]); + handleDontCloseX11DisplayQuirk(rendererQuirksES3[0]); + handleDontCloseX11DisplayQuirk(rendererQuirksES2[0]); + } + sr = new SharedResource(eglDevice[0], + madeCurrentES1[0], rendererQuirksES1[0], ctpES1[0], + madeCurrentES2[0], rendererQuirksES2[0], ctpES2[0], + madeCurrentES3[0], rendererQuirksES3[0], ctpES3[0], + madeCurrentGLn[0], rendererQuirksGLn[0], ctpGLn[0]); + if( initDefaultDevice ) { + defaultSharedResource = sr; + } } - final SharedResource sr = new SharedResource(defaultDevice, - madeCurrentGLn || madeCurrentES1 || madeCurrentES2 || madeCurrentES3, - rendererQuirksGLn[0], ctpGLn[0], - rendererQuirksES1[0], ctpES1[0], - rendererQuirksES3ES2[0], ctpES3ES2[0]); if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.createShared: devices: queried nativeTK "+QUERY_EGL_ES_NATIVE_TK+", adevice " + adevice + ", defaultDevice " + defaultDevice); - System.err.println("EGLDrawableFactory.createShared: context GLn: " + madeCurrentGLn + ", quirks "+rendererQuirksGLn[0]); - System.err.println("EGLDrawableFactory.createShared: context ES1: " + madeCurrentES1 + ", quirks "+rendererQuirksES1[0]); - System.err.println("EGLDrawableFactory.createShared: context ES2: " + madeCurrentES2 + ", quirks "+rendererQuirksES3ES2[0]); - System.err.println("EGLDrawableFactory.createShared: context ES3: " + madeCurrentES3 + ", quirks "+rendererQuirksES3ES2[0]); + System.err.println("EGLDrawableFactory.MapGLVersions: mapSuccess "+mapSuccess+", mappedToDefaultDevice "+mappedToDefaultDevice[0]); + System.err.println("EGLDrawableFactory.MapGLVersions: defDevice : " + defaultDevice); + System.err.println("EGLDrawableFactory.MapGLVersions: adevice : " + adevice); + System.err.println("EGLDrawableFactory.MapGLVersions: eglDevice : " + sr.device); + System.err.println("EGLDrawableFactory.MapGLVersions: context ES1: " + sr.isAvailableES1 + ", quirks "+sr.rendererQuirksES1); + System.err.println("EGLDrawableFactory.MapGLVersions: context ES2: " + sr.isAvailableES2 + ", quirks "+sr.rendererQuirksES2); + System.err.println("EGLDrawableFactory.MapGLVersions: context ES3: " + sr.isAvailableES3 + ", quirks "+sr.rendererQuirksES3); + System.err.println("EGLDrawableFactory.MapGLVersions: context GLn: " + sr.isAvailableGLn + ", quirks "+sr.rendererQuirksGLn); dumpMap(); } return sr; @@ -607,200 +656,218 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } private boolean mapAvailableEGLESConfig(final AbstractGraphicsDevice adevice, - final int[] majorVersion, final int[] minorVersion, - final int[] ctxProfile, final GLRendererQuirks[] rendererQuirks) { - final String profileString = EGLContext.getGLProfile(majorVersion[0], minorVersion[0], ctxProfile[0]); + final boolean[] mapsADeviceToDefaultDevice, + final EGLGraphicsDevice[] resEGLDevice) { + final int majorVersion = 2; + final int minorVersion = 0; + final int ctxProfile = EGLContext.CTX_PROFILE_ES; + final String profileString = EGLContext.getGLProfile(majorVersion, minorVersion, ctxProfile); if ( !GLProfile.isAvailable(adevice, profileString) ) { if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+profileString+" n/a on "+adevice); + System.err.println("EGLDrawableFactory.MapGLVersions: "+profileString+" n/a on "+adevice); } return false; } final GLProfile glp = GLProfile.get(adevice, profileString) ; final GLDrawableFactoryImpl desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getDesktopFactory(); - final boolean initDefaultDevice = 0 == defaultDevice.getHandle(); // Note: GLProfile always triggers EGL device initialization first! - final boolean mapsADeviceToDefaultDevice = !QUERY_EGL_ES_NATIVE_TK || initDefaultDevice || - null == desktopFactory; - // FIXME || adevice instanceof EGLGraphicsDevice ; + + final GLCapabilities reqCapsAny = new GLCapabilities(glp); + reqCapsAny.setRedBits(5); reqCapsAny.setGreenBits(5); reqCapsAny.setBlueBits(5); reqCapsAny.setAlphaBits(0); + reqCapsAny.setDoubleBuffered(false); + final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); + final List<GLCapabilitiesImmutable> defaultDevicePBufferCapsL = getAvailableEGLConfigs(defaultDevice, reqCapsPBuffer); + final boolean defaultDeviceHasPBuffer = defaultDevicePBufferCapsL.size() > 0; + + final boolean useDefaultDevice = adevice == defaultDevice; + + mapsADeviceToDefaultDevice[0] = !useDefaultDevice && + null != defaultSharedResource && defaultSharedResource.isAvailable && + defaultConnection.equals(adevice.getConnection()); + if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+profileString+" ( "+majorVersion[0]+" ), "+ - "mapsADeviceToDefaultDevice "+mapsADeviceToDefaultDevice+ - " (QUERY_EGL_ES_NATIVE_TK "+QUERY_EGL_ES_NATIVE_TK+", initDefaultDevice "+initDefaultDevice+", hasDesktopFactory "+(null != desktopFactory)+ + System.err.println("EGLDrawableFactory.MapGLVersions: "+profileString+" ( "+majorVersion+" ), "+ + "mapsADeviceToDefaultDevice "+mapsADeviceToDefaultDevice[0]+ + " (useDefaultDevice "+useDefaultDevice+", defaultDeviceHasPBuffer "+defaultDeviceHasPBuffer+", hasDesktopFactory "+(null != desktopFactory)+ ", isEGLGraphicsDevice "+(adevice instanceof EGLGraphicsDevice)+")"); } - boolean hasPBuffer; - EGLGraphicsDevice eglDevice = null; - EGLFeatures eglFeatures = null; - NativeSurface surface = null; - ProxySurface upstreamSurface = null; // X11, GLX, .. - ProxySurface downstreamSurface = null; // EGL + if( mapsADeviceToDefaultDevice[0] ) { + return true; + } + + final boolean defaultNoSurfacelessCtx = GLRendererQuirks.existStickyDeviceQuirk(defaultDevice, GLRendererQuirks.NoSurfacelessCtx); boolean success = false; - try { - final GLCapabilities reqCapsAny = new GLCapabilities(glp); - reqCapsAny.setRedBits(5); reqCapsAny.setGreenBits(5); reqCapsAny.setBlueBits(5); reqCapsAny.setAlphaBits(0); - reqCapsAny.setDoubleBuffered(false); - - if( mapsADeviceToDefaultDevice ) { - // In this branch, any non EGL device is mapped to EGL default shared resources (default behavior). - // Only one default shared resource instance is ever be created. - if( initDefaultDevice ) { - defaultDevice.open(); - defaultDeviceEGLFeatures = new EGLFeatures(defaultDevice); - - // Probe for GLRendererQuirks.SingletonEGLDisplayOnly - final long secondEGLDisplay = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY); - if ( EGL.EGL_NO_DISPLAY == secondEGLDisplay ) { - final int quirk = GLRendererQuirks.SingletonEGLDisplayOnly; - GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); - EGLDisplayUtil.setSingletonEGLDisplayOnly(true); + final boolean hasKHRSurfacelessTried; + if( defaultDeviceEGLFeatures.hasKHRSurfaceless && !defaultNoSurfacelessCtx ) { + hasKHRSurfacelessTried = true; + final AbstractGraphicsDevice zdevice = useDefaultDevice ? defaultDevice : adevice; // reuse + final EGLSurface zeroSurface = createSurfacelessImpl(zdevice, false, reqCapsAny, reqCapsAny, null, 64, 64); + resEGLDevice[0] = (EGLGraphicsDevice) zeroSurface.getGraphicsConfiguration().getScreen().getDevice(); + if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory-MapGLVersions.0: "+resEGLDevice[0]); + } + EGLDrawable zeroDrawable = null; + EGLContext context = null; + boolean hasException = false; + try { + zeroDrawable = (EGLDrawable) createOnscreenDrawableImpl ( zeroSurface ); + zeroDrawable.setRealized(true); + + context = (EGLContext) zeroDrawable.createContext(null); + if (null == context) { + throw new GLException("Couldn't create shared context for drawable: "+zeroDrawable); + } + // Triggers initial mapping, if not done yet + if( GLContext.CONTEXT_NOT_CURRENT != context.makeCurrent() ) { // could cause exception + // context.isCurrent() ! + final GL gl = context.getGL(); + final String glVersionString = gl.glGetString(GL.GL_VERSION); + if(null != glVersionString) { + success = true; + } else { + setNoSurfacelessCtxQuirk(context); + } + } else if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory-MapGLVersions.0: NOT_CURRENT: "+resEGLDevice[0]+", "+context); + } + } catch (final Throwable t) { + hasException = true; + if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory-MapGLVersions.0: INFO: context create/makeCurrent failed"); + t.printStackTrace(); + } + } finally { + if( null != context ) { + try { + context.destroy(); + } catch (final GLException gle) { if ( DEBUG_SHAREDCTX ) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Second eglGetDisplay(EGL_DEFAULT_DISPLAY) failed"); + System.err.println("EGLDrawableFactory-MapGLVersions.0: INFO: destroy caught exception:"); + gle.printStackTrace(); } } } - eglDevice = defaultDevice; // reuse + if( null != zeroDrawable ) { + zeroDrawable.setRealized(false); + } + if( null != zeroSurface ) { + zeroSurface.destroyNotify(); + } + if( success || hasException ) { // cont. using device if !success + if( defaultDevice != resEGLDevice[0] ) { // don't close default device + if(null != resEGLDevice[0]) { + resEGLDevice[0].close(); + } + } + } + } + if( success ) { + return true; + } + } else { // hasKHRSurfaceless + hasKHRSurfacelessTried = false; + } + EGLFeatures eglFeatures = null; + NativeSurface surface = null; + EGLDrawable drawable = null; + GLDrawable zeroDrawable = null; + EGLContext context = null; + ProxySurface upstreamSurface = null; // X11, GLX, .. + ProxySurface downstreamSurface = null; // EGL + try { + if( useDefaultDevice && defaultDeviceHasPBuffer ) { + // Map any non EGL device to EGL default shared resources (default behavior), using a pbuffer surface + resEGLDevice[0] = defaultDevice; // reuse eglFeatures = defaultDeviceEGLFeatures; if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig.0: "+eglFeatures); + System.err.println("EGLDrawableFactory-MapGLVersions.1: "+resEGLDevice[0]); + System.err.println("EGLDrawableFactory-MapGLVersions.1: "+eglFeatures); } - if( !glp.isGLES() && !eglFeatures.hasGLAPI ) { - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig() OpenGL API not supported (1)"); - } - } else { - final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); - final List<GLCapabilitiesImmutable> availablePBufferCapsL = getAvailableEGLConfigs(eglDevice, reqCapsPBuffer); - hasPBuffer = availablePBufferCapsL.size() > 0; - - // attempt to created the default shared resources .. - if( hasPBuffer ) { - // 2nd case create defaultDevice shared resource using pbuffer surface - downstreamSurface = createDummySurfaceImpl(eglDevice, false, reqCapsPBuffer, reqCapsPBuffer, null, 64, 64); // egl pbuffer offscreen - if( null != downstreamSurface ) { - downstreamSurface.createNotify(); - surface = downstreamSurface; - } - } else { - // 3rd case fake creation of defaultDevice shared resource, no pbuffer available - final List<GLCapabilitiesImmutable> capsAnyL = getAvailableEGLConfigs(eglDevice, reqCapsAny); - if(capsAnyL.size() > 0) { - final GLCapabilitiesImmutable chosenCaps = capsAnyL.get(0); - EGLContext.mapStaticGLESVersion(eglDevice, chosenCaps); - success = true; - } - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig() no pbuffer config available, detected !pbuffer config: "+success); - EGLGraphicsConfigurationFactory.printCaps("!PBufferCaps", capsAnyL, System.err); - } - } + downstreamSurface = createDummySurfaceImpl(resEGLDevice[0], false, reqCapsPBuffer, reqCapsPBuffer, null, 64, 64); + if( null != downstreamSurface ) { + downstreamSurface.createNotify(); + surface = downstreamSurface; } - } else { - // 4th case always creates a true mapping of given device to EGL + } else if( adevice != defaultDevice ) { + // Create a true mapping of given device to EGL upstreamSurface = desktopFactory.createDummySurface(adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window if(null != upstreamSurface) { upstreamSurface.createNotify(); - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); - eglDevice.open(); - eglFeatures = new EGLFeatures(eglDevice); + resEGLDevice[0] = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); + resEGLDevice[0].open(); + eglFeatures = new EGLFeatures(resEGLDevice[0]); if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig.1: "+eglFeatures); - } - if( !glp.isGLES() && !eglFeatures.hasGLAPI ) { - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig() OpenGL API not supported (2)"); - } - // disposed at finalized: eglDevice, upstreamSurface - } else { - hasPBuffer = true; - surface = upstreamSurface; + System.err.println("EGLDrawableFactory-MapGLVersions.2: "+resEGLDevice[0]); + System.err.println("EGLDrawableFactory-MapGLVersions.2: "+eglFeatures); } + surface = upstreamSurface; } } if(null != surface) { - EGLDrawable drawable = null; - GLDrawable zeroDrawable = null; - EGLContext context = null; - try { - drawable = (EGLDrawable) createOnscreenDrawableImpl ( surface ); - drawable.setRealized(true); - - context = (EGLContext) drawable.createContext(null); - if (null == context) { - throw new GLException("Couldn't create shared context for drawable: "+drawable); - } + drawable = (EGLDrawable) createOnscreenDrawableImpl ( surface ); + drawable.setRealized(true); - if( GLContext.CONTEXT_NOT_CURRENT != context.makeCurrent() ) { // could cause exception - // context.isCurrent() ! - final String glVersionString = context.getGL().glGetString(GL.GL_VERSION); - if(null != glVersionString) { - context.mapCurrentAvailableGLESVersion(eglDevice); - if(eglDevice != adevice) { - context.mapCurrentAvailableGLESVersion(adevice); - } + context = (EGLContext) drawable.createContext(null); + if (null == context) { + throw new GLException("Couldn't create shared context for drawable: "+drawable); + } - if( eglFeatures.hasKHRSurfaceless && - ( context.isGLES() || context.getGLVersionNumber().compareTo(GLContext.Version3_0) >= 0 ) - ) - { - if( probeSurfacelessCtx(context, false /* restoreDrawable */) ) { - zeroDrawable = context.getGLDrawable(); - } - } else { - setNoSurfacelessCtxQuirk(context); + // Triggers initial mapping, if not done yet + if( GLContext.CONTEXT_NOT_CURRENT != context.makeCurrent() ) { // could cause exception + // context.isCurrent() ! + final GL gl = context.getGL(); + final String glVersionString = gl.glGetString(GL.GL_VERSION); + if(null != glVersionString) { + success = true; + if( !hasKHRSurfacelessTried && eglFeatures.hasKHRSurfaceless && + ( context.isGLES() || context.getGLVersionNumber().compareTo(GLContext.Version3_0) >= 0 ) + ) + { + if( probeSurfacelessCtx(context, false /* restoreDrawable */) ) { + zeroDrawable = context.getGLDrawable(); } - rendererQuirks[0] = context.getRendererQuirks(); - ctxProfile[0] = context.getContextOptions(); - majorVersion[0] = context.getGLVersionNumber().getMajor(); - minorVersion[0] = context.getGLVersionNumber().getMinor(); - success = true; } else { - // Oops .. something is wrong - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+eglDevice+", "+context.getGLVersion()+" - VERSION is null, dropping availability!"); - } + setNoSurfacelessCtxQuirk(context); } + } else if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory-MapGLVersions.12: NULL VERSION: "+resEGLDevice[0]+", "+context.getGLVersion()); } - } catch (final Throwable t) { - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: INFO: context create/makeCurrent failed"); - t.printStackTrace(); - } - } finally { - if( null != context ) { - try { - context.destroy(); - } catch (final GLException gle) { - if ( DEBUG_SHAREDCTX ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: INFO: destroy caught exception:"); - gle.printStackTrace(); - } - } - } - if( null != zeroDrawable ) { - zeroDrawable.setRealized(false); - } - if( null != drawable ) { - drawable.setRealized(false); - } + } else if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory-MapGLVersions.12: NOT_CURRENT: "+resEGLDevice[0]+", "+context); } } } catch (final Throwable t) { if ( DEBUG_SHAREDCTX ) { - System.err.println("Caught exception on thread "+getThreadName()); + System.err.println("EGLDrawableFactory-MapGLVersions.12: INFO: context create/makeCurrent failed"); t.printStackTrace(); } success = false; } finally { - if(null != downstreamSurface) { + if( null != context ) { + try { + context.destroy(); + } catch (final GLException gle) { + if ( DEBUG_SHAREDCTX ) { + System.err.println("EGLDrawableFactory-MapGLVersions.12: INFO: destroy caught exception:"); + gle.printStackTrace(); + } + } + } + if( null != zeroDrawable ) { + zeroDrawable.setRealized(false); + } + if( null != drawable ) { + drawable.setRealized(false); + } + if( null != downstreamSurface ) { downstreamSurface.destroyNotify(); } - if( defaultDevice != eglDevice ) { // don't close default device - if(null != eglDevice) { - eglDevice.close(); + if( defaultDevice != resEGLDevice[0] ) { // don't close default device + if(null != resEGLDevice[0]) { + resEGLDevice[0].close(); } } if(null != upstreamSurface) { @@ -831,8 +898,44 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { public final boolean hasDefaultDeviceKHRCreateContext() { return defaultDeviceEGLFeatures.hasKHRCreateContext; } - public final boolean hasOpenGLAPISupport() { - return defaultDeviceEGLFeatures.hasGLAPI; + /** + * {@inheritDoc} + * <p> + * This factory may support native desktop OpenGL if {@link EGL#EGL_CLIENT_APIS} contains {@code OpenGL} + * <i>and</i> if {@code EGL_KHR_create_context} extension is supported. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { + /** + * It has been experienced w/ Mesa 10.3.2 (EGL 1.4/Gallium) + * that even though initial OpenGL context can be created w/o 'EGL_KHR_create_context', + * switching the API via 'eglBindAPI(EGL_OpenGL_API)' the latter 'eglCreateContext(..)' fails w/ EGL_BAD_ACCESS. + * Hence we require both: OpenGL API support _and_ 'EGL_KHR_create_context'. + */ + return null != eglGLnDynamicLookupHelper && + defaultDeviceEGLFeatures.hasGLAPI && defaultDeviceEGLFeatures.hasKHRCreateContext; + } + + /** + * {@inheritDoc} + * <p> + * This factory always supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * Return true if {@code EGL_KHR_create_context} extension is supported, + * see {@link #hasDefaultDeviceKHRCreateContext()}. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { + return hasDefaultDeviceKHRCreateContext(); } @Override @@ -843,7 +946,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { @Override public final boolean getIsDeviceCompatible(final AbstractGraphicsDevice device) { // via mappings (X11/WGL/.. -> EGL) we shall be able to handle all types. - return null != sharedMap ; // null!=eglES2DynamicLookupHelper || null!=eglES1DynamicLookupHelper; + return null != sharedResourceImplementation ; // null!=eglES2DynamicLookupHelper || null!=eglES1DynamicLookupHelper || ..; } private static List<GLCapabilitiesImmutable> getAvailableEGLConfigs(final EGLGraphicsDevice eglDisplay, final GLCapabilitiesImmutable caps) { @@ -885,24 +988,28 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - public GLDynamicLookupHelper getGLDynamicLookupHelper(final String esProfile) { + public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) { final GLDynamicLookupHelper res; - if ( GLProfile.GLES2 == esProfile || GLProfile.GLES3 == esProfile ) { + if ( EGLContext.isGLES2ES3(majorVersion, contextOptions) ) { res = eglES2DynamicLookupHelper; - } else if ( GLProfile.GLES1 == esProfile ) { + } else if ( EGLContext.isGLES1(majorVersion, contextOptions) ) { res = eglES1DynamicLookupHelper; - } else { + } else if( EGLContext.isGLDesktop(contextOptions) ) { res = eglGLnDynamicLookupHelper; + } else { + throw new IllegalArgumentException("neither GLES1, GLES2, GLES3 nor desktop GL has been specified: "+majorVersion+" ("+EGLContext.getGLProfile(new StringBuilder(), contextOptions).toString()); } - if( null == res ) { - throw new GLException("No lookup for esProfile "+esProfile); + if( DEBUG_SHAREDCTX ) { + if( null == res ) { + System.err.println("EGLDrawableFactory.getGLDynamicLookupHelper: NULL for profile "+majorVersion+" ("+EGLContext.getGLProfile(new StringBuilder(), contextOptions).toString()); + } } return res; } @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { - if(null == sharedMap) { // null == eglES1DynamicLookupHelper && null == eglES2DynamicLookupHelper + if(null == sharedResourceImplementation) { // null == eglES1DynamicLookupHelper && null == eglES2DynamicLookupHelper || .. return new ArrayList<GLCapabilitiesImmutable>(); // null } return EGLGraphicsConfigurationFactory.getAvailableCapabilities(this, device); @@ -942,9 +1049,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final GLCapabilitiesChooser chooser) { final EGLGraphicsDevice device; if( createNewDevice || ! (deviceReq instanceof EGLGraphicsDevice) ) { - final long nativeDisplayID = ( deviceReq instanceof EGLGraphicsDevice) ? - ( (EGLGraphicsDevice) deviceReq ).getNativeDisplayID() : deviceReq.getHandle() ; - device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(nativeDisplayID, deviceReq.getConnection(), deviceReq.getUnitID()); + device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(deviceReq); device.open(); ownDevice[0] = true; } else { @@ -960,7 +1065,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - protected final ProxySurface createMutableSurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + protected final EGLSurface createMutableSurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstreamHook) { final boolean[] ownDevice = { false }; @@ -969,14 +1074,14 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - public final ProxySurface createDummySurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + public final EGLSurface createDummySurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { chosenCaps = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(chosenCaps); // complete validation in EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(..) above return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new EGLDummyUpstreamSurfaceHook(width, height)); } @Override - public final ProxySurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + public final EGLSurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); final boolean[] ownDevice = { false }; @@ -1019,11 +1124,10 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - protected ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, + protected EGLSurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { - final EGLGraphicsDevice eglDeviceReq = (EGLGraphicsDevice) deviceReq; - final EGLGraphicsDevice device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID()); + final EGLGraphicsDevice device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(deviceReq); device.open(); final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final EGLGraphicsConfiguration cfg = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java index 6c11b3bdc..890dab8f7 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java @@ -1,5 +1,6 @@ package jogamp.opengl.egl; +import com.jogamp.common.ExceptionUtils; import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.ProxySurface; import com.jogamp.nativewindow.UpstreamSurfaceHook; @@ -8,6 +9,8 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.opengl.egl.EGL; +import jogamp.nativewindow.ProxySurfaceImpl; + /** Uses a PBuffer offscreen surface */ public class EGLDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { /** @@ -50,6 +53,11 @@ public class EGLDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize } eglDevice.lock(); try { + if( EGLDrawable.DEBUG ) { + System.err.println(EGLSurface.getThreadName()+": EGLDummyUpstreamSurfaceHook: EGL.eglDestroySurface: 0x"+Long.toHexString(s.getSurfaceHandle())); + ProxySurfaceImpl.dumpHierarchy(System.err, s); + ExceptionUtils.dumpStack(System.err); + } EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle()); s.setSurfaceHandle(EGL.EGL_NO_SURFACE); s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java index d37efc455..038194d58 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java @@ -31,6 +31,8 @@ package jogamp.opengl.egl; import java.util.ArrayList; import java.util.List; +import jogamp.nativewindow.BcmVCArtifacts; + /** * <p> * Covering ES3 and ES2. @@ -41,12 +43,20 @@ public final class EGLES2DynamicLibraryBundleInfo extends EGLDynamicLibraryBundl super(); } + @Override public final List<List<String>> getToolLibNames() { + final List<List<String>> libsList = new ArrayList<List<String>>(); { final List<String> libsGL = new ArrayList<String>(); + /** + * Prefer libGLESv2.so over libGLESv2.so.2 for proprietary + * Broadcom graphics when the VC4 DRM Xorg driver isn't present + */ + final boolean bcm_vc_iv_quirk = BcmVCArtifacts.guessVCIVUsed(); + // ES3: This is the default lib name, according to the spec libsGL.add("libGLESv3.so.3"); @@ -63,12 +73,18 @@ public final class EGLES2DynamicLibraryBundleInfo extends EGLDynamicLibraryBundl libsGL.add("libGLES30"); // ES2: This is the default lib name, according to the spec - libsGL.add("libGLESv2.so.2"); + if (!bcm_vc_iv_quirk) { + libsGL.add("libGLESv2.so.2"); + } // ES2: Try these as well, if spec fails libsGL.add("libGLESv2.so"); libsGL.add("GLESv2"); + if (bcm_vc_iv_quirk) { + libsGL.add("libGLESv2.so.2"); + } + // ES2: Alternative names libsGL.add("GLES20"); libsGL.add("GLESv2_CM"); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java index d10263f22..5505fed52 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java @@ -242,7 +242,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact } ownEGLDisplay = false; } else { - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(absDevice.getHandle(), absDevice.getConnection(), absDevice.getUnitID()); + eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(absDevice); eglDevice.open(); ownEGLDisplay = true; } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java b/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java index e4e692fb2..8956bcbd9 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java @@ -35,7 +35,7 @@ import com.jogamp.nativewindow.ProxySurface; import com.jogamp.nativewindow.UpstreamSurfaceHook; import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLException; - +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; import com.jogamp.opengl.egl.EGL; @@ -101,16 +101,22 @@ public class EGLSurface extends WrappedSurface { final boolean isPBuffer = ((GLCapabilitiesImmutable) config.getChosenCapabilities()).isPBuffer(); long eglSurface = createEGLSurfaceHandle(isPBuffer, true /* useSurfaceHandle */, config, nativeSurface); + if( DEBUG ) { + System.err.println(getThreadName() + ": EGLSurface: EGL.eglCreateSurface.0: 0x"+Long.toHexString(eglSurface)); + ProxySurfaceImpl.dumpHierarchy(System.err, this); + } + if ( EGL.EGL_NO_SURFACE == eglSurface ) { final int eglError0 = EGL.eglGetError(); if( EGL.EGL_BAD_NATIVE_WINDOW == eglError0 && !isPBuffer ) { // Try window handle if available and differs (Windows HDC / HWND). // ANGLE impl. required HWND on Windows. if( hasUniqueNativeWindowHandle(nativeSurface) ) { - if(DEBUG) { + eglSurface = createEGLSurfaceHandle(isPBuffer, false /* useSurfaceHandle */, config, nativeSurface); + if( DEBUG ) { System.err.println(getThreadName() + ": Info: Creation of window surface w/ surface handle failed: "+config+", error "+GLDrawableImpl.toHexString(eglError0)+", retry w/ windowHandle"); + System.err.println(getThreadName() + ": EGLSurface: EGL.eglCreateSurface.1: 0x"+Long.toHexString(eglSurface)); } - eglSurface = createEGLSurfaceHandle(isPBuffer, false /* useSurfaceHandle */, config, nativeSurface); if (EGL.EGL_NO_SURFACE == eglSurface) { throw new GLException("Creation of window surface w/ window handle failed: "+config+", "+this+", error "+GLDrawableImpl.toHexString(EGL.eglGetError())); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index d4fc0b005..995ff870e 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -63,6 +63,7 @@ import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.GLFBODrawableImpl; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -85,6 +86,8 @@ public class MacOSXCGLContext extends GLContextImpl // NSOpenGL-based or CGL-based) protected interface GLBackendImpl { boolean isNSContext(); + /** Indicating CALayer, i.e. onscreen rendering using offscreen layer. */ + boolean isUsingCALayer(); long create(long share, int ctp, int major, int minor); boolean destroy(long ctx); void associateDrawable(boolean bound); @@ -108,6 +111,9 @@ public class MacOSXCGLContext extends GLContextImpl } static boolean isGLProfileSupported(final int ctp, final int major, final int minor) { + if( 0 != ( CTX_PROFILE_ES & ctp ) ) { + return false; + } final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; final boolean ctCore = 0 != ( CTX_PROFILE_CORE & ctp ) ; @@ -423,12 +429,33 @@ public class MacOSXCGLContext extends GLContextImpl } @Override - protected boolean setSwapIntervalImpl(final int interval) { - return impl.setSwapInterval(interval); + protected final Integer setSwapIntervalImpl2(final int interval) { + if( !impl.isUsingCALayer() && !drawable.getChosenGLCapabilities().isOnscreen() ) { + return null; + } + final int useInterval; + if( 0 > interval ) { + useInterval = Math.abs(interval); + } else { + useInterval = interval; + } + if( impl.setSwapInterval(useInterval) ) { + return Integer.valueOf(useInterval); + } + return null; } + /** + * {@inheritDoc} + * <p> + * Ignoring {@code contextFQN}, using {@code MacOSX}-{@link AbstractGraphicsDevice#getUniqueID()}. + * </p> + */ @Override - protected final void updateGLXProcAddressTable() { + protected final void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh) { + if( null == dlh ) { + throw new GLException("No GLDynamicLookupHelper for "+this); + } final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "MacOSX-"+adevice.getUniqueID(); @@ -446,7 +473,7 @@ public class MacOSXCGLContext extends GLContextImpl } } else { cglExtProcAddressTable = new CGLExtProcAddressTable(new GLProcAddressResolver()); - resetProcAddressTable(getCGLExtProcAddressTable()); + resetProcAddressTable(getCGLExtProcAddressTable(), dlh); synchronized(mappedContextTypeObjectLock) { mappedGLXProcAddress.put(key, getCGLExtProcAddressTable()); if(DEBUG) { @@ -521,6 +548,8 @@ public class MacOSXCGLContext extends GLContextImpl @Override public boolean isNSContext() { return true; } + @Override + public boolean isUsingCALayer() { return null != backingLayerHost; } /** Only returns a valid NSView. If !NSView, return null and mark either isPBuffer, isFBO or isSurfaceless. */ private long getNSViewHandle(final boolean[] isPBuffer, final boolean[] isFBO, final boolean[] isSurfaceless) { @@ -547,7 +576,7 @@ public class MacOSXCGLContext extends GLContextImpl nsViewHandle = OSXUtil.GetNSView(drawableHandle); } else if( isPBuffer[0] ) { nsViewHandle = 0; - } else if( isSurfacelessOK() ) { + } else if( isSurfaceless() ) { isSurfaceless[0] = true; nsViewHandle = 0; } else { @@ -1128,6 +1157,9 @@ public class MacOSXCGLContext extends GLContextImpl public boolean isNSContext() { return false; } @Override + public boolean isUsingCALayer() { return false; } + + @Override public long create(final long share, final int ctp, final int major, final int minor) { long ctx = 0; final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index ab1d56e29..871067f4c 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -148,7 +148,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - public GLDynamicLookupHelper getGLDynamicLookupHelper(final String profileName) { + public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) { return macOSXCGLDynamicLookupHelper; } @@ -335,6 +335,33 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return null; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * Always returns true. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return true; } + @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return MacOSXCGLGraphicsConfiguration.getAvailableCapabilities(this, device); diff --git a/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java b/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java index 562d4883d..bdd9b6c95 100644 --- a/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java +++ b/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java @@ -195,11 +195,21 @@ public class ALAudioSink implements AudioSink { clearPreALError("init."+checkErrIter++); preferredAudioFormat = new AudioFormat(querySampleRate(), DefaultFormat.sampleSize, DefaultFormat.channelCount, DefaultFormat.signed, DefaultFormat.fixedP, DefaultFormat.planar, DefaultFormat.littleEndian); if( DEBUG ) { - System.out.println("ALAudioSink: OpenAL Extensions:"+al.alGetString(ALConstants.AL_EXTENSIONS)); + final int[] alcvers = { 0, 0 }; + System.out.println("ALAudioSink: OpenAL Version: "+al.alGetString(ALConstants.AL_VERSION)); + System.out.println("ALAudioSink: OpenAL Extensions: "+al.alGetString(ALConstants.AL_EXTENSIONS)); clearPreALError("init."+checkErrIter++); - System.out.println("ALAudioSink: Null device OpenAL Extensions:"+alc.alcGetString(null, ALCConstants.ALC_EXTENSIONS)); + System.out.println("ALAudioSink: Null device OpenALC:"); + alc.alcGetIntegerv(null, ALCConstants.ALC_MAJOR_VERSION, 1, alcvers, 0); + alc.alcGetIntegerv(null, ALCConstants.ALC_MINOR_VERSION, 1, alcvers, 1); + System.out.println(" Version: "+alcvers[0]+"."+alcvers[1]); + System.out.println(" Extensions: "+alc.alcGetString(null, ALCConstants.ALC_EXTENSIONS)); clearPreALError("init."+checkErrIter++); - System.out.println("ALAudioSink: Device "+deviceSpecifier+" OpenAL Extensions:"+alc.alcGetString(device, ALCConstants.ALC_EXTENSIONS)); + System.out.println("ALAudioSink: Device "+deviceSpecifier+" OpenALC:"); + alc.alcGetIntegerv(device, ALCConstants.ALC_MAJOR_VERSION, 1, alcvers, 0); + alc.alcGetIntegerv(device, ALCConstants.ALC_MINOR_VERSION, 1, alcvers, 1); + System.out.println(" Version: "+alcvers[0]+"."+alcvers[1]); + System.out.println(" Extensions: "+alc.alcGetString(device, ALCConstants.ALC_EXTENSIONS)); System.out.println("ALAudioSink: hasSOFTBufferSamples "+hasSOFTBufferSamples); System.out.println("ALAudioSink: hasALC_thread_local_context "+hasALC_thread_local_context); System.out.println("ALAudioSink: preferredAudioFormat "+preferredAudioFormat); @@ -310,12 +320,14 @@ public class ALAudioSink implements AudioSink { final int alSrcName = null != alSource ? alSource[0] : 0; final int alBuffersLen = null != alBufferNames ? alBufferNames.length : 0; final int ctxHash = context != null ? context.hashCode() : 0; + final int alFramesAvailSize = alFramesAvail != null ? alFramesAvail.size() : 0; + final int alFramesPlayingSize = alFramesPlaying != null ? alFramesPlaying.size() : 0; return "ALAudioSink[init "+initialized+", playRequested "+playRequested+", device "+deviceSpecifier+", ctx "+toHexString(ctxHash)+", alSource "+alSrcName+ ", chosen "+chosenFormat+ ", al[chan "+ALHelpers.alChannelLayoutName(alChannelLayout)+", type "+ALHelpers.alSampleTypeName(alSampleType)+ ", fmt "+toHexString(alFormat)+", soft "+hasSOFTBufferSamples+ - "], playSpeed "+playSpeed+", buffers[total "+alBuffersLen+", avail "+alFramesAvail.size()+", "+ - "queued["+alFramesPlaying.size()+", apts "+getPTS()+", "+getQueuedTime() + " ms, " + alBufferBytesQueued+" bytes], "+ + "], playSpeed "+playSpeed+", buffers[total "+alBuffersLen+", avail "+alFramesAvailSize+", "+ + "queued["+alFramesPlayingSize+", apts "+getPTS()+", "+getQueuedTime() + " ms, " + alBufferBytesQueued+" bytes], "+ "queue[g "+frameGrowAmount+", l "+frameLimit+"]"; } diff --git a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java index cfecbfd8d..f09d289fa 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java +++ b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java @@ -46,10 +46,14 @@ import com.jogamp.opengl.GLProfile; import jogamp.opengl.Debug; import com.jogamp.common.net.UriQueryProps; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.net.Uri; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.LFRingbuffer; import com.jogamp.common.util.Ringbuffer; +import com.jogamp.common.util.SourcedInterruptedException; import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.util.TimeFrameI; import com.jogamp.opengl.util.av.AudioSink; @@ -365,7 +369,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { event_mask = addStateEventMask(event_mask, GLMediaPlayer.State.Paused); setState( State.Paused ); if( null != streamWorker ) { - streamWorker.doPause(); + streamWorker.doPause(true); } if( flush ) { resetAVPTSAndFlush(); @@ -414,7 +418,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { final State _state = state; setState( State.Paused ); if( null != streamWorker ) { - streamWorker.doPause(); + streamWorker.doPause(true); } // Adjust target .. if( msec >= duration ) { @@ -571,7 +575,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { this.vid = vid; this.aid = aid; - new Thread() { + new InterruptSource.Thread() { public void run() { try { // StreamWorker may be used, see API-doc of StreamWorker @@ -968,8 +972,9 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { * shall be <code>null</code> for audio only. * @return the last processed video PTS value, maybe {@link TimeFrameI#INVALID_PTS} if video frame is invalid or n/a. * Will be {@link TimeFrameI#END_OF_STREAM_PTS} if end of stream reached. + * @throws InterruptedException if waiting for next frame fails */ - protected abstract int getNextTextureImpl(GL gl, TextureFrame nextFrame); + protected abstract int getNextTextureImpl(GL gl, TextureFrame nextFrame) throws InterruptedException; protected final int getNextSingleThreaded(final GL gl, final TextureFrame nextFrame, final boolean[] gotVFrame) throws InterruptedException { final int pts; @@ -1064,7 +1069,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { * {@link GLMediaPlayerImpl#updateAttributes(int, int, int, int, int, int, int, float, int, int, int, String, String) updateAttributes(..)}, * the latter decides whether StreamWorker is being used. */ - class StreamWorker extends Thread { + class StreamWorker extends InterruptSource.Thread { private volatile boolean isRunning = false; private volatile boolean isActive = false; private volatile boolean isBlocked = false; @@ -1086,13 +1091,13 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { setDaemon(true); synchronized(this) { start(); - while( !isRunning ) { + try { this.notifyAll(); // wake-up startup-block - try { + while( !isRunning && !shallStop ) { this.wait(); // wait until started - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } } } @@ -1140,18 +1145,20 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { sharedGLCtx.release(); } } - public final synchronized void doPause() { + public final synchronized void doPause(final boolean waitUntilDone) { if( isActive ) { shallPause = true; - if( Thread.currentThread() != this ) { + if( java.lang.Thread.currentThread() != this ) { if( isBlocked && isActive ) { this.interrupt(); } - while( isActive && isRunning ) { + if( waitUntilDone ) { try { - this.wait(); // wait until paused + while( isActive && isRunning ) { + this.wait(); // wait until paused + } } catch (final InterruptedException e) { - e.printStackTrace(); + throw new InterruptedRuntimeException(e); } } } @@ -1160,14 +1167,16 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { public final synchronized void doResume() { if( isRunning && !isActive ) { shallPause = false; - if( Thread.currentThread() != this ) { - while( !isActive && !shallPause && isRunning ) { + if( java.lang.Thread.currentThread() != this ) { + try { this.notifyAll(); // wake-up pause-block - try { + while( !isActive && !shallPause && isRunning ) { this.wait(); // wait until resumed - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + final InterruptedException e2 = SourcedInterruptedException.wrap(e); + doPause(false); + throw new InterruptedRuntimeException(e2); } } } @@ -1175,17 +1184,17 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { public final synchronized void doStop() { if( isRunning ) { shallStop = true; - if( Thread.currentThread() != this ) { + if( java.lang.Thread.currentThread() != this ) { if( isBlocked && isRunning ) { this.interrupt(); } - while( isRunning ) { + try { this.notifyAll(); // wake-up pause-block (opt) - try { + while( isRunning ) { this.wait(); // wait until stopped - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } } } @@ -1203,48 +1212,48 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { this.notifyAll(); // wake-up ctor() } - while( !shallStop ){ - if( shallPause ) { - synchronized ( this ) { - if( sharedGLCtxCurrent ) { - postNextTextureImpl(sharedGLCtx.getGL()); - sharedGLCtx.release(); - } - while( shallPause && !shallStop ) { - isActive = false; - this.notifyAll(); // wake-up doPause() - try { - this.wait(); // wait until resumed - } catch (final InterruptedException e) { - if( !shallPause ) { - e.printStackTrace(); + while( !shallStop ) { + TextureFrame nextFrame = null; + try { + if( shallPause ) { + synchronized ( this ) { + if( sharedGLCtxCurrent ) { + postNextTextureImpl(sharedGLCtx.getGL()); + sharedGLCtx.release(); + } + while( shallPause && !shallStop ) { + isActive = false; + this.notifyAll(); // wake-up doPause() + try { + this.wait(); // wait until resumed + } catch (final InterruptedException e) { + if( !shallPause ) { + throw SourcedInterruptedException.wrap(e); + } } } + if( sharedGLCtxCurrent ) { + makeCurrent(sharedGLCtx); + preNextTextureImpl(sharedGLCtx.getGL()); + } + isActive = true; + this.notifyAll(); // wake-up doResume() } - if( sharedGLCtxCurrent ) { - makeCurrent(sharedGLCtx); - preNextTextureImpl(sharedGLCtx.getGL()); - } - isActive = true; - this.notifyAll(); // wake-up doResume() } - } - if( !sharedGLCtxCurrent && null != sharedGLCtx ) { - synchronized ( this ) { - if( null != sharedGLCtx ) { - makeCurrent( sharedGLCtx ); - preNextTextureImpl(sharedGLCtx.getGL()); - sharedGLCtxCurrent = true; - } - if( null == videoFramesFree ) { - throw new InternalError("XXX videoFramesFree is null"); + if( !sharedGLCtxCurrent && null != sharedGLCtx ) { + synchronized ( this ) { + if( null != sharedGLCtx ) { + makeCurrent( sharedGLCtx ); + preNextTextureImpl(sharedGLCtx.getGL()); + sharedGLCtxCurrent = true; + } + if( null == videoFramesFree ) { + throw new InternalError("XXX videoFramesFree is null"); + } } } - } - if( !shallStop ) { - TextureFrame nextFrame = null; - try { + if( !shallStop ) { isBlocked = true; final GL gl; if( STREAM_ID_NONE != vid ) { @@ -1260,7 +1269,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { if( TimeFrameI.INVALID_PTS != vPTS ) { if( null != nextFrame ) { if( STREAM_WORKER_DELAY > 0 ) { - Thread.sleep(STREAM_WORKER_DELAY); + java.lang.Thread.sleep(STREAM_WORKER_DELAY); } if( !videoFramesDecoded.put(nextFrame) ) { throw new InternalError("XXX: free "+videoFramesFree+", decoded "+videoFramesDecoded+", "+GLMediaPlayerImpl.this); @@ -1294,31 +1303,30 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_EOS); } - } catch (final InterruptedException e) { - isBlocked = false; - if( !shallStop && !shallPause ) { - streamErr = new StreamException("InterruptedException while decoding: "+GLMediaPlayerImpl.this.toString(), e); - } - } catch (final Throwable t) { - streamErr = new StreamException(t.getClass().getSimpleName()+" while decoding: "+GLMediaPlayerImpl.this.toString(), t); - } finally { - if( null != nextFrame ) { // put back - videoFramesFree.put(nextFrame); + } + } catch (final InterruptedException e) { + if( !isBlocked ) { // !shallStop && !shallPause + streamErr = new StreamException("InterruptedException while decoding: "+GLMediaPlayerImpl.this.toString(), + SourcedInterruptedException.wrap(e)); + } + isBlocked = false; + } catch (final Throwable t) { + streamErr = new StreamException(t.getClass().getSimpleName()+" while decoding: "+GLMediaPlayerImpl.this.toString(), t); + } finally { + if( null != nextFrame ) { // put back + videoFramesFree.put(nextFrame); + } + if( null != streamErr ) { + if( DEBUG ) { + ExceptionUtils.dumpThrowable("handled", streamErr); } - if( null != streamErr ) { - if( DEBUG ) { - final Throwable t = null != streamErr.getCause() ? streamErr.getCause() : streamErr; - System.err.println("Caught StreamException: "+t.getMessage()); - t.printStackTrace(); - } - // state transition incl. notification - synchronized ( this ) { - shallPause = true; - isActive = false; - this.notifyAll(); // wake-up potential do*() - } - pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_ERR); + // state transition incl. notification + synchronized ( this ) { + shallPause = true; + isActive = false; + this.notifyAll(); // wake-up potential do*() } + pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_ERR); } } } @@ -1379,6 +1387,16 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } } + /** + * Called initially by {@link #initStreamImpl(int, int)}, which + * is called off-thread by {@link #initStream(Uri, int, int, int)}. + * <p> + * The latter catches an occurring exception and set the state delivers the error events. + * </p> + * <p> + * Further calls are issues off-thread by the decoder implementation. + * </p> + */ protected final void updateAttributes(int vid, final int aid, final int width, final int height, final int bps_stream, final int bps_video, final int bps_audio, final float fps, final int videoFrames, final int audioFrames, final int duration, final String vcodec, final String acodec) { @@ -1413,7 +1431,12 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { this.fps = fps; if( 0 != fps ) { this.frame_duration = 1000f / fps; - this.maxNullFrameCountUntilEOS = MAX_FRAMELESS_MS_UNTIL_EOS / (int)this.frame_duration; + final int fdurI = (int)this.frame_duration; + if( 0 < fdurI ) { + this.maxNullFrameCountUntilEOS = MAX_FRAMELESS_MS_UNTIL_EOS / fdurI; + } else { + this.maxNullFrameCountUntilEOS = MAX_FRAMELESS_UNTIL_EOS_DEFAULT; + } } else { this.frame_duration = 0; this.maxNullFrameCountUntilEOS = MAX_FRAMELESS_UNTIL_EOS_DEFAULT; @@ -1524,7 +1547,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { final int decVideoFrames = null != videoFramesDecoded ? videoFramesDecoded.size() : 0; final int video_scr = video_scr_pts + (int) ( ( Platform.currentTimeMillis() - video_scr_t0 ) * playSpeed ); final String camPath = null != cameraPath ? ", camera: "+cameraPath : ""; - return "GLMediaPlayer["+state+", vSCR "+video_scr+", frames[p "+presentedFrameCount+", d "+decodedFrameCount+", t "+videoFrames+" ("+tt+" s), z "+nullFrameCount+" / "+maxNullFrameCountUntilEOS+"], "+ + return getClass().getSimpleName()+"["+state+", vSCR "+video_scr+", frames[p "+presentedFrameCount+", d "+decodedFrameCount+", t "+videoFrames+" ("+tt+" s), z "+nullFrameCount+" / "+maxNullFrameCountUntilEOS+"], "+ "speed "+playSpeed+", "+bps_stream+" bps, hasSW "+(null!=streamWorker)+ ", Texture[count "+textureCount+", free "+freeVideoFrames+", dec "+decVideoFrames+", tagt "+toHexString(textureTarget)+", ifmt "+toHexString(textureInternalFormat)+", fmt "+toHexString(textureFormat)+", type "+toHexString(textureType)+"], "+ "Video[id "+vid+", <"+vcodec+">, "+width+"x"+height+", glOrient "+isInGLOrientation+", "+fps+" fps, "+frame_duration+" fdur, "+bps_video+" bps], "+ diff --git a/src/jogl/classes/jogamp/opengl/util/av/VideoPixelFormat.java b/src/jogl/classes/jogamp/opengl/util/av/VideoPixelFormat.java index 44d83e78d..db8da6157 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/VideoPixelFormat.java +++ b/src/jogl/classes/jogamp/opengl/util/av/VideoPixelFormat.java @@ -64,7 +64,7 @@ public enum VideoPixelFormat { XVMC_MPEG2_MC, /** */ XVMC_MPEG2_IDCT, - /** packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 */ + /** packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 ( sharing Cb and Cr w/ 2 pixels ) */ UYVY422, /** packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 */ UYYVYY411, diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java index f294d5bc0..6a4257ade 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGDynamicLibraryBundleInfo.java @@ -37,7 +37,7 @@ import java.util.List; import java.util.Set; import com.jogamp.opengl.GLProfile; - +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.DynamicLibraryBundle; import com.jogamp.common.os.DynamicLibraryBundleInfo; import com.jogamp.common.util.RunnableExecutor; @@ -190,7 +190,8 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { libLoaded[i] = dl.isToolLibLoaded(i); } if( !libLoaded[LIB_IDX_UTI] || !libLoaded[LIB_IDX_FMT] || !libLoaded[LIB_IDX_COD] ) { - throw new RuntimeException("FFMPEG Tool library incomplete: [ avutil "+libLoaded[LIB_IDX_UTI]+", avformat "+libLoaded[LIB_IDX_FMT]+", avcodec "+libLoaded[LIB_IDX_COD]+"]"); + System.err.println("FFMPEG Tool library incomplete: [ avutil "+libLoaded[LIB_IDX_UTI]+", avformat "+libLoaded[LIB_IDX_FMT]+", avcodec "+libLoaded[LIB_IDX_COD]+"]"); + return null; } dl.claimAllLinkPermission(); try { @@ -216,7 +217,10 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { throw new InternalError("XXX0 "+symbolNames.length+" != "+symbolCount); } - AccessController.doPrivileged(privInitSymbolsAction); + final DynamicLibraryBundle dl = AccessController.doPrivileged(privInitSymbolsAction); + if( null == dl ) { + return false; + } // optional symbol name set final Set<String> optionalSymbolNameSet = new HashSet<String>(); @@ -254,7 +258,7 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { try { _ready = initSymbols(_versions); } catch (final Throwable t) { - t.printStackTrace(); + ExceptionUtils.dumpThrowable("", t); } libsUFCLoaded = libLoaded[LIB_IDX_UTI] && libLoaded[LIB_IDX_FMT] && libLoaded[LIB_IDX_COD]; avUtilVersion = _versions[0]; @@ -328,6 +332,16 @@ class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { } @Override + public final boolean searchToolLibInSystemPath() { + return true; + } + + @Override + public final boolean searchToolLibSystemPathFirst() { + return true; + } + + @Override public final List<List<String>> getToolLibNames() { final List<List<String>> libsList = new ArrayList<List<String>>(); diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java index 7df5d6a9e..b5cccdb6d 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/FFMPEGMediaPlayer.java @@ -106,11 +106,12 @@ import jogamp.opengl.util.av.VideoPixelFormat; * <p> * Currently we are binary compatible w/: * <table border="1"> - * <tr><th>libav / ffmpeg</th><th>lavc</th><th>lavf</th><th>lavu</th><th>lavr/lswr</th> <th>FFMPEG* class</th></tr> + * <tr><th>libav / ffmpeg</th><th>lavc</th><th>lavf</th><th>lavu</th><th>lavr/lswr</th> <th>FFMPEG* class</th></tr> * <tr><td>0.8</td> <td>53</td> <td>53</td> <td>51</td> <td></td> <td>FFMPEGv08</td></tr> * <tr><td>9.0 / 1.2</td> <td>54</td> <td>54</td> <td>52</td> <td>01/00</td> <td>FFMPEGv09</td></tr> * <tr><td>10 / 2.[0-3]</td> <td>55</td> <td>55</td> <td>53/52</td> <td>01/00</td> <td>FFMPEGv10</td></tr> - * <tr><td>11 / 2.[4-x]</td> <td>56</td> <td>56</td> <td>54</td> <td>02/01</td> <td>FFMPEGv11</td></tr> + * <tr><td>11 / 2.[4-8]</td> <td>56</td> <td>56</td> <td>54</td> <td>02/01</td> <td>FFMPEGv11</td></tr> + * <tr><td>12 / 2.[9-x]</td> <td>57</td> <td>57</td> <td>55</td> <td>02/01</td> <td>TODO</td></tr> * </table> * </p> * <p> @@ -145,17 +146,28 @@ import jogamp.opengl.util.av.VideoPixelFormat; * <li>GNU/Linux: ffmpeg or libav are deployed in most distributions.</li> * <li>Windows: * <ul> + * <li>https://ffmpeg.org/download.html#build-windows</li> * <li>http://ffmpeg.zeranoe.com/builds/ (ffmpeg) <i>recommended, works w/ dshow</i></li> * <li>http://win32.libav.org/releases/ (libav)</li> * </ul></li> - * <li>MacOSX using Homebrew + * <li>MacOSX * <ul> - * <li>https://github.com/Homebrew/homebrew/wiki/Installation</li> - * <li>https://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX</li> + * <li>Building using Homebrew * + * <ul> + * <li>https://github.com/Homebrew/homebrew/wiki/Installation</li> + * <li>https://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX<pre> +ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install ffmpeg + * </pre></li> + * </ul></li> + * <li>Builds + * <ul> + * <li>https://ffmpeg.org/download.html#build-mac</li> + * </ul></li> * </ul></li> * <li>OpenIndiana/Solaris:<pre> - * pkg set-publisher -p http://pkg.openindiana.org/sfe-encumbered. - * pkt install pkg:/video/ffmpeg +pkg set-publisher -p http://pkg.openindiana.org/sfe-encumbered. +pkt install pkg:/video/ffmpeg * </pre></li> * </ul> * </p> @@ -337,12 +349,10 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { resStreamLocS = dev_video_linux + cameraPath.decode(); break; case WINDOWS: - resStreamLocS = cameraPath.decode(); - break; case MACOS: case OPENKODE: default: - resStreamLocS = streamLocS; // FIXME: ?? + resStreamLocS = cameraPath.decode(); break; } if( null != cameraProps ) { @@ -436,9 +446,10 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { } break; - case 2: if( vPixelFmt == VideoPixelFormat.YUYV422 ) { + case 2: if( vPixelFmt == VideoPixelFormat.YUYV422 || vPixelFmt == VideoPixelFormat.UYVY422 ) { // YUYV422: // < packed YUV 4:2:2, 2x 16bpp, Y0 Cb Y1 Cr - // Stuffed into RGBA half width texture + // UYVY422: // < packed YUV 4:2:2, 2x 16bpp, Cb Y0 Cr Y1 + // Both stuffed into RGBA half width texture tf = GL.GL_RGBA; tif=GL.GL_RGBA; break; } else { tf = GL2ES2.GL_RG; tif=GL2ES2.GL_RG; break; @@ -606,6 +617,7 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { texWidth = vTexWidth[0] + vTexWidth[1] + vTexWidth[2]; texHeight = vH; break; case YUYV422: // < packed YUV 4:2:2, 2x 16bpp, Y0 Cb Y1 Cr - stuffed into RGBA half width texture + case UYVY422: // < packed YUV 4:2:2, 2x 16bpp, Cb Y0 Cr Y1 - stuffed into RGBA half width texture case BGR24: usesTexLookupShader = true; texWidth = vTexWidth[0]; texHeight = vH; @@ -764,6 +776,29 @@ public class FFMPEGMediaPlayer extends GLMediaPlayerImpl { " return vec4(r, g, b, 1);\n"+ "}\n" ; + case UYVY422: // < packed YUV 4:2:2, 2 x 16bpp, Cb Y0 Cr Y1 + // Stuffed into RGBA half width texture + return + "vec4 "+texLookupFuncName+"(in "+getTextureSampler2DType()+" image, in vec2 texCoord) {\n"+ + " "+ + " float y1,u,y2,v,y,r,g,b;\n"+ + " vec2 tc_halfw = vec2(texCoord.x*0.5, texCoord.y);\n"+ + " vec4 uyvy = texture2D(image, tc_halfw).rgba;\n"+ + " u = uyvy.r;\n"+ + " y1 = uyvy.g;\n"+ + " v = uyvy.b;\n"+ + " y2 = uyvy.a;\n"+ + " y = mix( y1, y2, mod(gl_FragCoord.x, 2) ); /* avoid branching! */\n"+ + " y = 1.1643*(y-0.0625);\n"+ + " u = u-0.5;\n"+ + " v = v-0.5;\n"+ + " r = y+1.5958*v;\n"+ + " g = y-0.39173*u-0.81290*v;\n"+ + " b = y+2.017*u;\n"+ + " return vec4(r, g, b, 1);\n"+ + "}\n" + ; + case BGR24: return "vec4 "+texLookupFuncName+"(in "+getTextureSampler2DType()+" image, in vec2 texCoord) {\n"+ diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColor.fp b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColor.fp index 22dd1e61a..516aa0f6f 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColor.fp +++ b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColor.fp @@ -6,10 +6,10 @@ #define mgl_FragColor gl_FragColor #endif -#include es_precision.glsl +#include "es_precision.glsl" -#include mgl_uniform.glsl -#include mgl_varying.glsl +#include "mgl_uniform.glsl" +#include "mgl_varying.glsl" #include mgl_alphatest.fp diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColorTexture.fp b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColorTexture.fp index 130711e19..8a610f062 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColorTexture.fp +++ b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/shaders/FixedFuncColorTexture.fp @@ -8,14 +8,14 @@ #endif -#include es_precision.glsl -#include mgl_lightdef.glsl +#include "es_precision.glsl" +#include "mgl_lightdef.glsl" -#include mgl_const.glsl -#include mgl_uniform.glsl -#include mgl_varying.glsl +#include "mgl_const.glsl" +#include "mgl_uniform.glsl" +#include "mgl_varying.glsl" -#include mgl_alphatest.fp +#include "mgl_alphatest.fp" const float gamma = 1.5; // FIXME const vec3 igammav = vec3(1.0 / gamma); // FIXME diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java index a8269ad5c..fd0db7c04 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java @@ -50,15 +50,19 @@ import com.jogamp.nativewindow.NativeSurface; import com.jogamp.opengl.GLContext; import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.GLRendererQuirks; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; +import jogamp.opengl.GLXExtensions; public class WindowsWGLContext extends GLContextImpl { static final Map<String, String> extensionNameMap; @@ -70,7 +74,8 @@ public class WindowsWGLContext extends GLContextImpl { // Table that holds the addresses of the native C-language entry points for // WGL extension functions. private WGLExtProcAddressTable wglExtProcAddressTable; - private int hasSwapIntervalSGI = 0; + /** 2 WGL_EXT_swap_control_tear, 1 WGL_EXT_swap_control, 0 undefined, -1 none */ + private int hasSwapInterval = 0; private int hasSwapGroupNV = 0; static { @@ -93,7 +98,7 @@ public class WindowsWGLContext extends GLContextImpl { wglGLReadDrawableAvailable=false; // no inner state _wglExt=null; wglExtProcAddressTable=null; - hasSwapIntervalSGI = 0; + hasSwapInterval = 0; hasSwapGroupNV = 0; super.resetStates(isInit); } @@ -198,20 +203,37 @@ public class WindowsWGLContext extends GLContextImpl { @Override protected long createContextARBImpl(final long share, final boolean direct, final int ctp, final int major, final int minor) { + if(DEBUG) { + System.err.println(getThreadName()+" - WindowWGLContext.createContextARBImpl: "+getGLVersion(major, minor, ctp, "@creation") + + ", handle "+toHexString(drawable.getHandle()) + ", share "+toHexString(share)+", direct "+direct); + } + final boolean ctDesktopGL = 0 == ( CTX_PROFILE_ES & ctp ); + final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; + final boolean ctFwdCompat = 0 != ( CTX_OPTION_FORWARD & ctp ) ; + final boolean ctDebug = 0 != ( CTX_OPTION_DEBUG & ctp ) ; + if( !ctDesktopGL ) { + if(DEBUG) { + System.err.println(getThreadName() + ": WindowWGLContext.createContextARBImpl: GL ES not avail "+getGLVersion(major, minor, ctp, "@creation")); + } + return 0; // n/a + } if( null == getWGLExtProcAddressTable()) { - updateGLXProcAddressTable(); + final GLDynamicLookupHelper dlh = getGLDynamicLookupHelper(major, ctp); + if( null == dlh ) { + if(DEBUG) { + System.err.println(getThreadName()+" - WindowWGLContext.createContextARBImpl: Null GLDynamicLookupHelper"); + } + return 0; + } else { + updateGLXProcAddressTable(null, dlh); + } } final WGLExt _wglExt = getWGLExt(); if(DEBUG) { - System.err.println(getThreadName()+" - WindowWGLContext.createContextARBImpl: "+getGLVersion(major, minor, ctp, "@creation") + - ", handle "+toHexString(drawable.getHandle()) + ", share "+toHexString(share)+", direct "+direct+ + System.err.println(getThreadName()+" - WindowWGLContext.createContextARBImpl: "+ ", wglCreateContextAttribsARB: "+toHexString(wglExtProcAddressTable._addressof_wglCreateContextAttribsARB)); } - final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; - final boolean ctFwdCompat = 0 != ( CTX_OPTION_FORWARD & ctp ) ; - final boolean ctDebug = 0 != ( CTX_OPTION_DEBUG & ctp ) ; - long ctx=0; final int idx_flags = 4; @@ -294,6 +316,11 @@ public class WindowsWGLContext extends GLContextImpl { "], bitmap "+glCaps.isBitmap()+" -> "+createContextARBAvailable+ "], shared "+sharedCreatedWithARB+"]"); } + final GLProfile glp = glCaps.getGLProfile(); + if( glp.isGLES() ) { + throw new GLException(getThreadName()+": Unable to create OpenGL ES context on desktopDevice "+device+ + ", config "+config+", "+glp+", shareWith "+toHexString(shareWithHandle)); + } boolean createContextARBTried = false; // utilize the shared context's GLXExt in case it was using the ARB method and it already exists @@ -438,8 +465,17 @@ public class WindowsWGLContext extends GLContextImpl { } } + /** + * {@inheritDoc} + * <p> + * Ignoring {@code contextFQN}, using {@code WGL}-{@link AbstractGraphicsDevice#getUniqueID()}. + * </p> + */ @Override - protected final void updateGLXProcAddressTable() { + protected final void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh) { + if( null == dlh ) { + throw new GLException("No GLDynamicLookupHelper for "+this); + } final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "WGL-"+adevice.getUniqueID(); @@ -462,7 +498,7 @@ public class WindowsWGLContext extends GLContextImpl { } } else { wglExtProcAddressTable = new WGLExtProcAddressTable(new GLProcAddressResolver()); - resetProcAddressTable(wglExtProcAddressTable); + resetProcAddressTable(wglExtProcAddressTable, dlh); synchronized(mappedContextTypeObjectLock) { mappedGLXProcAddress.put(key, getWGLExtProcAddressTable()); if(DEBUG) { @@ -487,19 +523,42 @@ public class WindowsWGLContext extends GLContextImpl { } @Override - protected boolean setSwapIntervalImpl(final int interval) { - final WGLExt wglExt = getWGLExt(); - if(0==hasSwapIntervalSGI) { + protected final Integer setSwapIntervalImpl2(final int interval) { + if( !drawable.getChosenGLCapabilities().isOnscreen() ) { + return null; + } + if( 0 == hasSwapInterval ) { try { - hasSwapIntervalSGI = wglExt.isExtensionAvailable("WGL_EXT_swap_control")?1:-1; - } catch (final Throwable t) { hasSwapIntervalSGI=1; } + if ( isExtensionAvailable(GLXExtensions.WGL_EXT_swap_control) ) { + hasSwapInterval = 1; + if ( isExtensionAvailable(GLXExtensions.WGL_EXT_swap_control_tear) ) { + hasSwapInterval = 2; + if(DEBUG) { System.err.println("WGLContext.setSwapInterval.2 using: "+GLXExtensions.WGL_EXT_swap_control_tear + ", " + GLXExtensions.WGL_EXT_swap_control_tear); } + } else { + hasSwapInterval = 1; + if(DEBUG) { System.err.println("WGLContext.setSwapInterval.1 using: "+GLXExtensions.WGL_EXT_swap_control); } + } + } else { + hasSwapInterval = -1; + if(DEBUG) { System.err.println("WGLContext.setSwapInterval.0 N/A"); } + } + } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } } } - if (hasSwapIntervalSGI>0) { + if ( 0 < hasSwapInterval ) { // 2 || 1 + final int useInterval; + if( 1 == hasSwapInterval && 0 > interval ) { + useInterval = Math.abs(interval); + } else { + useInterval = interval; + } try { - return wglExt.wglSwapIntervalEXT(interval); - } catch (final Throwable t) { hasSwapIntervalSGI=-1; } + final WGLExt wglExt = getWGLExt(); + if( wglExt.wglSwapIntervalEXT(useInterval) ) { + return Integer.valueOf(useInterval); + } + } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } } } - return false; + return null; } private final int initSwapGroupImpl(final WGLExt wglExt) { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index 932c81f5d..652184e7e 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -44,8 +44,6 @@ import java.nio.Buffer; import java.nio.ShortBuffer; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Collection; -import java.util.HashMap; import java.util.List; import com.jogamp.nativewindow.AbstractGraphicsConfiguration; @@ -191,11 +189,10 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } catch (final Exception jre) { /* n/a .. */ } } - sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); - // Init shared resources off thread // Will be released via ShutdownHook - sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); + sharedResourceImplementation = new SharedResourceImplementation(); + sharedResourceRunner = new SharedResourceRunner(sharedResourceImplementation); sharedResourceRunner.start(); } } @@ -215,9 +212,9 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { sharedResourceRunner.stop(); sharedResourceRunner = null; } - if(null != sharedMap) { - sharedMap.clear(); - sharedMap = null; + if(null != sharedResourceImplementation) { + sharedResourceImplementation.clear(); + sharedResourceImplementation = null; } defaultDevice = null; /** @@ -231,15 +228,15 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - public GLDynamicLookupHelper getGLDynamicLookupHelper(final String profileName) { + public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) { return windowsWGLDynamicLookupHelper; } /* pp */ static String toHexString(final long l) { return "0x"+Long.toHexString(l); } private WindowsGraphicsDevice defaultDevice; + private SharedResourceImplementation sharedResourceImplementation; private SharedResourceRunner sharedResourceRunner; - private HashMap<String /*connection*/, SharedResourceRunner.Resource> sharedMap; @Override protected void enterThreadCriticalZone() { @@ -300,26 +297,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { final boolean hasReadDrawable() { return hasARBReadDrawable; } } - class SharedResourceImplementation implements SharedResourceRunner.Implementation { - @Override - public void clear() { - sharedMap.clear(); - } - @Override - public SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { - return sharedMap.put(device.getConnection(), resource); - } - @Override - public SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { - return sharedMap.get(device.getConnection()); - } - @Override - public Collection<SharedResourceRunner.Resource> mapValues() { - synchronized(sharedMap) { - return sharedMap.values(); - } - } - + class SharedResourceImplementation extends SharedResourceRunner.AImplementation { @Override public boolean isDeviceSupported(final AbstractGraphicsDevice device) { return true; @@ -465,6 +443,33 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { return null; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * Always returns true. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return true; } + @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return WindowsWGLGraphicsConfigurationFactory.getAvailableCapabilities(this, device); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java index f88718d1b..4ffe6e7d1 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -171,24 +171,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio ": error code " + GDI.GetLastError()); } if( !caps.isBackgroundOpaque() ) { - final long hwnd = GDI.WindowFromDC(hdc); - final DWM_BLURBEHIND bb = DWM_BLURBEHIND.create(); - bb.setDwFlags(GDI.DWM_BB_ENABLE| GDI.DWM_BB_TRANSITIONONMAXIMIZED); - bb.setFEnable( 1 ); - boolean ok = GDI.DwmEnableBlurBehindWindow(hwnd, bb); - if( ok ) { - final MARGINS m = MARGINS.create(); - m.setCxLeftWidth(-1); - m.setCxRightWidth(-1); - m.setCyBottomHeight(-1); - m.setCyTopHeight(-1); - ok = GDI.DwmExtendFrameIntoClientArea(hwnd, m); - } - if(DEBUG) { - final boolean isUndecorated = GDIUtil.IsUndecorated(hwnd); - final boolean isChild = GDIUtil.IsChild(hwnd); - System.err.println("translucency enabled on wnd: 0x"+Long.toHexString(hwnd)+" - isUndecorated "+isUndecorated+", isChild "+isChild+", ok: "+ok); - } + GDIUtil.DwmSetupTranslucency(GDI.WindowFromDC(hdc), true); } if (DEBUG) { System.err.println("setPixelFormat: hdc "+toHexString(hdc) +", "+caps); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index 21eb6b8f3..99268f13f 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -56,6 +56,7 @@ import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.GLRendererQuirks; import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.windows.PIXELFORMATDESCRIPTOR; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLGraphicsConfigurationFactory; @@ -349,7 +350,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } final GLCapabilitiesImmutable capsChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities(); - final boolean isOpaque = capsChosen.isBackgroundOpaque() && GDI.DwmIsCompositionEnabled(); + final boolean isOpaque = capsChosen.isBackgroundOpaque() && GDIUtil.DwmIsCompositionEnabled(); final int winattrbits = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen) & ~GLGraphicsConfigurationUtil.BITMAP_BIT; // w/o BITMAP final GLProfile glProfile = capsChosen.getGLProfile(); @@ -358,7 +359,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat if(DEBUG) { System.err.println("updateGraphicsConfigurationARB: hdc "+toHexString(hdc)+", pfdIDCount(hdc) "+pfdIDCount+", capsChosen "+capsChosen+", "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrbits).toString()); - System.err.println("\tisOpaque "+isOpaque+" (translucency requested: "+(!capsChosen.isBackgroundOpaque())+", compositioning enabled: "+GDI.DwmIsCompositionEnabled()+")"); + System.err.println("\tisOpaque "+isOpaque+" (translucency requested: "+(!capsChosen.isBackgroundOpaque())+", compositioning enabled: "+GDIUtil.DwmIsCompositionEnabled()+")"); final int pformatsNum = null != pformats ? pformats.length : -1; System.err.println("\textHDC "+extHDC+", chooser "+(null!=chooser)+", pformatsNum "+pformatsNum); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index 63b0b35c0..24f2ab8dd 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -56,6 +56,7 @@ import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.GLXExtensions; import com.jogamp.common.ExceptionUtils; @@ -72,7 +73,7 @@ public class X11GLXContext extends GLContextImpl { // Table that holds the addresses of the native C-language entry points for // GLX extension functions. private GLXExtProcAddressTable glXExtProcAddressTable; - /** 1 MESA, 2 SGI, 0 undefined, -1 none */ + /** 3 SGI, 2 GLX_EXT_swap_control_tear, 1 GLX_EXT_swap_control, 0 undefined, -1 none */ private int hasSwapInterval = 0; private int hasSwapGroupNV = 0; @@ -224,17 +225,34 @@ public class X11GLXContext extends GLContextImpl { @Override protected long createContextARBImpl(final long share, final boolean direct, final int ctp, final int major, final int minor) { - updateGLXProcAddressTable(); - final GLXExt _glXExt = getGLXExt(); if(DEBUG) { System.err.println(getThreadName()+": X11GLXContext.createContextARBImpl: "+getGLVersion(major, minor, ctp, "@creation") + - ", handle "+toHexString(drawable.getHandle()) + ", share "+toHexString(share)+", direct "+direct+ - ", glXCreateContextAttribsARB: "+toHexString(glXExtProcAddressTable._addressof_glXCreateContextAttribsARB)); + ", handle "+toHexString(drawable.getHandle()) + ", share "+toHexString(share)+", direct "+direct); } - + final boolean ctDesktopGL = 0 == ( CTX_PROFILE_ES & ctp ); final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; final boolean ctFwdCompat = 0 != ( CTX_OPTION_FORWARD & ctp ) ; final boolean ctDebug = 0 != ( CTX_OPTION_DEBUG & ctp ) ; + if( !ctDesktopGL ) { + if(DEBUG) { + System.err.println(getThreadName() + ": X11GLXContext.createContextARBImpl: GL ES not avail "+getGLVersion(major, minor, ctp, "@creation")); + } + return 0; // n/a + } + final GLDynamicLookupHelper dlh = getGLDynamicLookupHelper(major, ctp); + if( null == dlh ) { + if(DEBUG) { + System.err.println(getThreadName()+" - X11GLXContext.createContextARBImpl: Null GLDynamicLookupHelper"); + } + return 0; + } else { + updateGLXProcAddressTable(null, dlh); + } + final GLXExt _glXExt = getGLXExt(); + if(DEBUG) { + System.err.println(getThreadName()+": X11GLXContext.createContextARBImpl: "+ + ", glXCreateContextAttribsARB: "+toHexString(glXExtProcAddressTable._addressof_glXCreateContextAttribsARB)); + } final IntBuffer attribs = Buffers.newDirectIntBuffer(ctx_arb_attribs_rom); attribs.put(ctx_arb_attribs_idx_major + 1, major); @@ -322,6 +340,10 @@ public class X11GLXContext extends GLContextImpl { "], fbCfg "+config.hasFBConfig()+" -> "+createContextARBAvailable+ "], shared "+sharedCreatedWithARB+"]"); } + if( glp.isGLES() ) { + throw new GLException(getThreadName()+": Unable to create OpenGL ES context on desktopDevice "+device+ + ", config "+config+", "+glp+", shareWith "+toHexString(shareWithHandle)); + } if( !config.hasFBConfig() ) { // not able to use FBConfig -> GLX 1.1 @@ -479,8 +501,17 @@ public class X11GLXContext extends GLContextImpl { // Should check for X errors and raise GLException } + /** + * {@inheritDoc} + * <p> + * Ignoring {@code contextFQN}, using {@code GLX}+{@link AbstractGraphicsDevice#getUniqueID()}. + * </p> + */ @Override - protected final void updateGLXProcAddressTable() { + protected final void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh) { + if( null == dlh ) { + throw new GLException("No GLDynamicLookupHelper for "+this); + } final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "GLX-"+adevice.getUniqueID(); @@ -498,7 +529,7 @@ public class X11GLXContext extends GLContextImpl { } } else { glXExtProcAddressTable = new GLXExtProcAddressTable(new GLProcAddressResolver()); - resetProcAddressTable(getGLXExtProcAddressTable()); + resetProcAddressTable(getGLXExtProcAddressTable(), dlh); synchronized(mappedContextTypeObjectLock) { mappedGLXProcAddress.put(key, getGLXExtProcAddressTable()); if(DEBUG) { @@ -549,39 +580,67 @@ public class X11GLXContext extends GLContextImpl { } @Override - protected boolean setSwapIntervalImpl(final int interval) { - if( !drawable.getChosenGLCapabilities().isOnscreen() ) { return false; } - - final GLXExt glXExt = getGLXExt(); - if(0==hasSwapInterval) { + protected final Integer setSwapIntervalImpl2(final int interval) { + if( !drawable.getChosenGLCapabilities().isOnscreen() ) { + return null; + } + final long displayHandle = drawable.getNativeSurface().getDisplayHandle(); + if( 0 == hasSwapInterval ) { try { - /** Same impl. .. - if( glXExt.isExtensionAvailable(GLXExtensions.GLX_MESA_swap_control) ) { - if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval using: "+GLXExtensions.GLX_MESA_swap_control); } - hasSwapInterval = 1; - } else */ - if ( glXExt.isExtensionAvailable(GLXExtensions.GLX_SGI_swap_control) ) { - if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval using: "+GLXExtensions.GLX_SGI_swap_control); } - hasSwapInterval = 2; + if ( isExtensionAvailable(GLXExtensions.GLX_EXT_swap_control) ) { + hasSwapInterval = 1; + if ( isExtensionAvailable(GLXExtensions.GLX_EXT_swap_control_tear) ) { + try { + final IntBuffer val = Buffers.newDirectIntBuffer(1); + GLX.glXQueryDrawable(displayHandle, drawable.getHandle(), GLX.GLX_LATE_SWAPS_TEAR_EXT, val); + if( 1 == val.get(0) ) { + hasSwapInterval = 2; + if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval.2 using: "+GLXExtensions.GLX_EXT_swap_control_tear + ", " + GLXExtensions.GLX_EXT_swap_control_tear); } + } else if(DEBUG) { + System.err.println("X11GLXContext.setSwapInterval.2 n/a: "+GLXExtensions.GLX_EXT_swap_control_tear+", query: "+val.get(0)); + } + } catch (final Throwable t) { if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } } + } + if(DEBUG) { + if( 1 == hasSwapInterval ) { + System.err.println("X11GLXContext.setSwapInterval.1 using: "+GLXExtensions.GLX_EXT_swap_control); + } + } + } else if ( isExtensionAvailable(GLXExtensions.GLX_SGI_swap_control) ) { + hasSwapInterval = 3; + if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval.3 using: "+GLXExtensions.GLX_SGI_swap_control); } } else { hasSwapInterval = -1; + if(DEBUG) { System.err.println("X11GLXContext.setSwapInterval.0 N/A"); } } - } catch (final Throwable t) { hasSwapInterval=-1; } + } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } } } - /* try { - switch( hasSwapInterval ) { - case 1: - return 0 == glXExt.glXSwapIntervalMESA(interval); - case 2: - return 0 == glXExt.glXSwapIntervalSGI(interval); + if (3 == hasSwapInterval) { + final int useInterval; + if( 0 > interval ) { + useInterval = Math.abs(interval); + } else { + useInterval = interval; + } + try { + final GLXExt glXExt = getGLXExt(); + if( 0 == glXExt.glXSwapIntervalSGI(useInterval) ) { + return Integer.valueOf(useInterval); + } + } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } } + } else if ( 0 < hasSwapInterval ) { // 2 || 1 + final int useInterval; + if( 1 == hasSwapInterval && 0 > interval ) { + useInterval = Math.abs(interval); + } else { + useInterval = interval; } - } catch (Throwable t) { hasSwapInterval = -1; } */ - if (2 == hasSwapInterval) { try { - return 0 == glXExt.glXSwapIntervalSGI(interval); - } catch (final Throwable t) { hasSwapInterval=-1; } + GLX.glXSwapIntervalEXT(displayHandle, drawable.getHandle(), useInterval); + return Integer.valueOf(useInterval); + } catch (final Throwable t) { hasSwapInterval=-1; if(DEBUG) { ExceptionUtils.dumpThrowable("", t); } } } - return false; + return null; } private final int initSwapGroupImpl(final GLXExt glXExt) { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index ecaf20d86..a03ce1641 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -41,8 +41,6 @@ import java.nio.Buffer; import java.nio.ShortBuffer; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Collection; -import java.util.HashMap; import java.util.List; import com.jogamp.nativewindow.AbstractGraphicsConfiguration; @@ -126,11 +124,10 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { // The act of constructing them causes them to be registered X11GLXGraphicsConfigurationFactory.registerFactory(); - sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); - // Init shared resources off thread // Will be released via ShutdownHook - sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); + sharedResourceImplementation = new SharedResourceImplementation(); + sharedResourceRunner = new SharedResourceRunner(sharedResourceImplementation); sharedResourceRunner.start(); } } @@ -149,9 +146,9 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { sharedResourceRunner.stop(); sharedResourceRunner = null; } - if(null != sharedMap) { - sharedMap.clear(); - sharedMap = null; + if(null != sharedResourceImplementation) { + sharedResourceImplementation.clear(); + sharedResourceImplementation = null; } defaultDevice = null; /** @@ -163,13 +160,13 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } @Override - public final GLDynamicLookupHelper getGLDynamicLookupHelper(final String profileName) { + public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) { return x11GLXDynamicLookupHelper; } private X11GraphicsDevice defaultDevice; + private SharedResourceImplementation sharedResourceImplementation; private SharedResourceRunner sharedResourceRunner; - private HashMap<String /* connection */, SharedResourceRunner.Resource> sharedMap; static class SharedResource implements SharedResourceRunner.Resource { private final String glXServerVendorName; @@ -226,24 +223,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { final boolean isGLXMultisampleAvailable() { return glXMultisampleAvailable; } } - class SharedResourceImplementation implements SharedResourceRunner.Implementation { - @Override - public void clear() { - sharedMap.clear(); - } - @Override - public SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { - return sharedMap.put(device.getConnection(), resource); - } - @Override - public SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { - return sharedMap.get(device.getConnection()); - } - @Override - public Collection<SharedResourceRunner.Resource> mapValues() { - return sharedMap.values(); - } - + class SharedResourceImplementation extends SharedResourceRunner.AImplementation { @Override public boolean isDeviceSupported(final AbstractGraphicsDevice device) { final boolean res; @@ -399,6 +379,33 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return 0; } + /** + * {@inheritDoc} + * <p> + * This factory always supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * Always returns true. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return true; } + @Override protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { return X11GLXGraphicsConfigurationFactory.getAvailableCapabilities(this, device); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java index 86349b645..8f7d710cd 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java @@ -275,21 +275,6 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem return val; } - static XRenderDirectFormat XVisual2XRenderMask(final long dpy, final long visual) { - final XRenderPictFormat renderPictFmt = X11Lib.XRenderFindVisualFormat(dpy, visual); - if(null == renderPictFmt) { - return null; - } - return renderPictFmt.getDirect(); - } - static XRenderDirectFormat XVisual2XRenderMask(final long dpy, final long visual, final XRenderPictFormat dest) { - if( !X11Lib.XRenderFindVisualFormat(dpy, visual, dest) ) { - return null; - } else { - return dest.getDirect(); - } - } - static X11GLCapabilities GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final long fbcfg, final int winattrmask, final boolean isMultisampleAvailable) { final IntBuffer tmp = Buffers.newDirectIntBuffer(1); diff --git a/src/jogl/native/GLDebugMessageHandler.c b/src/jogl/native/GLDebugMessageHandler.c index 5c18b94b1..e524df9bf 100644 --- a/src/jogl/native/GLDebugMessageHandler.c +++ b/src/jogl/native/GLDebugMessageHandler.c @@ -17,6 +17,7 @@ #define DBG_PRINT(...) #endif +// Note: 'ARB' is also used for 'KHR'! static jmethodID glDebugMessageARB = NULL; // int source, int type, int id, int severity, String msg static jmethodID glDebugMessageAMD = NULL; // int id, int category, int severity, String msg @@ -120,7 +121,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_opengl_GLDebugMessageHandler_register0 handle->extType = extType; DBG_PRINT("GLDebugMessageHandler.register0: jobject %p, extType %d\n", (void*)handle->obj, handle->extType); - if(jogamp_opengl_GLDebugMessageHandler_EXT_ARB == extType) { + if(jogamp_opengl_GLDebugMessageHandler_EXT_KHR == extType || + jogamp_opengl_GLDebugMessageHandler_EXT_ARB == extType) { _local_PFNGLDEBUGMESSAGECALLBACKARBPROC ptr_glDebugMessageCallbackARB; ptr_glDebugMessageCallbackARB = (_local_PFNGLDEBUGMESSAGECALLBACKARBPROC) (intptr_t) procAddress; ptr_glDebugMessageCallbackARB((_local_GLDEBUGPROCARB)GLDebugMessageARBCallback, handle); @@ -151,7 +153,8 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_GLDebugMessageHandler_unregister0 JoglCommon_throwNewRuntimeException(env, "wrong handle (obj doesn't match)"); } - if(jogamp_opengl_GLDebugMessageHandler_EXT_ARB == handle->extType) { + if(jogamp_opengl_GLDebugMessageHandler_EXT_KHR == handle->extType || + jogamp_opengl_GLDebugMessageHandler_EXT_ARB == handle->extType) { _local_PFNGLDEBUGMESSAGECALLBACKARBPROC ptr_glDebugMessageCallbackARB; ptr_glDebugMessageCallbackARB = (_local_PFNGLDEBUGMESSAGECALLBACKARBPROC) (intptr_t) procAddress; ptr_glDebugMessageCallbackARB((_local_GLDEBUGPROCARB)NULL, NULL); diff --git a/src/jogl/native/libav/ffmpeg_impl_template.c b/src/jogl/native/libav/ffmpeg_impl_template.c index ca283ef52..d02770eb7 100644 --- a/src/jogl/native/libav/ffmpeg_impl_template.c +++ b/src/jogl/native/libav/ffmpeg_impl_template.c @@ -622,6 +622,7 @@ static const char * inFmtNames[] = { "video4linux", // linux (old) "dshow", // windows "vfwcap", // windows (old) + "avfoundation", // osx "mpg", "yuv2", "mjpeg", @@ -732,6 +733,9 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0) fprintf(stderr, "Camera %d not found\n", devIdx); } } + if(pAV->verbose) { + fprintf(stderr, "Camera: Filename: %s\n", filename); + } const char *sizeS = NULL != jSizeS ? (*env)->GetStringUTFChars(env, jSizeS, &iscopy) : NULL; int hasSize = 0; @@ -756,6 +760,7 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0) } sp_av_dict_set(&inOpts, "framerate", buffer, 0); } + // FIXME pre-select: sp_av_dict_set(&inOpts, "pixel_format", "yuyv422", 0); } MY_MUTEX_LOCK(env, mutex_avcodec_openclose); @@ -1148,8 +1153,10 @@ JNIEXPORT void JNICALL FF_FUNC(setStream0) #endif } else { vLinesize[0] = pAV->pVFrame->linesize[0]; - if( pAV->vPixFmt == PIX_FMT_YUYV422 ) { - // Stuff 2x 16bpp (YUYV) into one RGBA pixel! + if( pAV->vPixFmt == PIX_FMT_YUYV422 || + pAV->vPixFmt == PIX_FMT_UYVY422 ) + { + // Stuff 2x 16bpp (YUYV, UYVY) into one RGBA pixel! pAV->vTexWidth[0] = pAV->pVCodecCtx->width / 2; } else { pAV->vTexWidth[0] = pAV->pVCodecCtx->width; diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java index 070b6bb28..56c196132 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java @@ -45,6 +45,23 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice protected ToolkitLock toolkitLock; /** + * Return the default display connection for the given windowing toolkit type + * gathered via {@link NativeWindowFactory#getDefaultDisplayConnection()}. + * @param type + */ + public static String getDefaultDisplayConnection() { + return NativeWindowFactory.getDefaultDisplayConnection(); + } + /** + * Return the default display connection for the given windowing toolkit type + * gathered via {@link NativeWindowFactory#getDefaultDisplayConnection(String)}. + * @param type + */ + public static String getDefaultDisplayConnection(final String type) { + return NativeWindowFactory.getDefaultDisplayConnection(type); + } + + /** * Create an instance with the system default {@link ToolkitLock}, * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String)}. * @param type diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java index 63c79af55..cbf3e22da 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java @@ -42,7 +42,7 @@ public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen } public static AbstractGraphicsScreen createDefault(final String type) { - return new DefaultGraphicsScreen(new DefaultGraphicsDevice(type, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT), 0); + return new DefaultGraphicsScreen(new DefaultGraphicsDevice(type, DefaultGraphicsDevice.getDefaultDisplayConnection(type), AbstractGraphicsDevice.DEFAULT_UNIT), 0); } @Override diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java index 8f841e7ea..9dc3f2d4b 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java @@ -42,6 +42,7 @@ package com.jogamp.nativewindow; /** A generic exception for OpenGL errors used throughout the binding as a substitute for {@link RuntimeException}. */ +@SuppressWarnings("serial") public class NativeWindowException extends RuntimeException { /** Constructs a NativeWindowException object. */ public NativeWindowException() { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java index d01e3a203..323bc8c86 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java @@ -33,7 +33,6 @@ package com.jogamp.nativewindow; -import java.io.File; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -43,9 +42,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.jogamp.nativewindow.util.Point; import com.jogamp.nativewindow.util.PointImmutable; import jogamp.common.os.PlatformPropsImpl; +import jogamp.nativewindow.BcmVCArtifacts; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NativeWindowFactoryImpl; import jogamp.nativewindow.ToolkitProperties; @@ -54,13 +55,16 @@ import jogamp.nativewindow.WrappedWindow; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -79,28 +83,28 @@ public abstract class NativeWindowFactory { protected static final boolean DEBUG; /** OpenKODE/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ - public static final String TYPE_EGL = ".egl".intern(); + public static final String TYPE_EGL = ".egl"; /** Microsoft Windows type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_WINDOWS = ".windows".intern(); + public static final String TYPE_WINDOWS = ".windows"; /** X11 type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_X11 = ".x11".intern(); + public static final String TYPE_X11 = ".x11"; /** Broadcom VC IV/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_BCM_VC_IV = ".bcm.vc.iv".intern(); + public static final String TYPE_BCM_VC_IV = ".bcm.vc.iv"; /** Android/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ - public static final String TYPE_ANDROID = ".android".intern(); + public static final String TYPE_ANDROID = ".android"; /** Mac OS X type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_MACOSX = ".macosx".intern(); + public static final String TYPE_MACOSX = ".macosx"; /** Generic AWT type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_AWT = ".awt".intern(); + public static final String TYPE_AWT = ".awt"; /** Generic DEFAULT type, where platform implementation don't care, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_DEFAULT = ".default".intern(); + public static final String TYPE_DEFAULT = ".default"; private static final String nativeWindowingTypePure; // canonical String via String.intern() private static final String nativeWindowingTypeCustom; // canonical String via String.intern() @@ -133,20 +137,6 @@ public abstract class NativeWindowFactory { protected NativeWindowFactory() { } - private static final boolean guessBroadcomVCIV() { - return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { - private final File vcliblocation = new File( - "/opt/vc/lib/libbcm_host.so"); - @Override - public Boolean run() { - if ( vcliblocation.isFile() ) { - return Boolean.TRUE; - } - return Boolean.FALSE; - } - } ).booleanValue(); - } - private static String _getNativeWindowingType() { switch(PlatformPropsImpl.OS_TYPE) { case ANDROID: @@ -163,7 +153,7 @@ public abstract class NativeWindowFactory { case SUNOS: case HPUX: default: - if( guessBroadcomVCIV() ) { + if( BcmVCArtifacts.guessVCIVUsed() ) { return TYPE_BCM_VC_IV; } return TYPE_X11; @@ -181,7 +171,7 @@ public abstract class NativeWindowFactory { _DEBUG[0] = Debug.debug("NativeWindow"); _tmp[0] = PropertyAccess.getProperty("nativewindow.ws.name", true); Runtime.getRuntime().addShutdownHook( - new Thread(new Runnable() { + new InterruptSource.Thread(null, new Runnable() { @Override public void run() { NativeWindowFactory.shutdown(true); @@ -647,6 +637,17 @@ public abstract class NativeWindowFactory { VisualIDHolder.VID_UNDEFINED != visualID ; } + public static String getDefaultDisplayConnection() { + return getDefaultDisplayConnection(NativeWindowFactory.getNativeWindowType(true)); + } + public static String getDefaultDisplayConnection(final String nwt) { + if(NativeWindowFactory.TYPE_X11 == nwt) { + return X11Util.getNullDisplayName(); + } else { + return AbstractGraphicsDevice.DEFAULT_CONNECTION; + } + } + /** * Creates a native device type, following {@link #getNativeWindowType(boolean) getNativeWindowType(true)}. * <p> @@ -673,11 +674,32 @@ public abstract class NativeWindowFactory { return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT); } } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { - return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } else if( NativeWindowFactory.TYPE_EGL == nwt ) { - throw new UnsupportedOperationException("n/a for windowing system: "+nwt); + final EGLGraphicsDevice device; + if( own ) { + Object odev = null; + try { + // EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + odev = ReflectionUtil.callStaticMethod("jogamp.opengl.egl.EGLDisplayUtil", "eglCreateEGLGraphicsDevice", + new Class<?>[] { Long.class, String.class, Integer.class}, + new Object[] { 0L /* EGL.EGL_DEFAULT_DISPLAY */, DefaultGraphicsDevice.getDefaultDisplayConnection(nwt), AbstractGraphicsDevice.DEFAULT_UNIT }, + NativeWindowFactory.class.getClassLoader()); + } catch (final Exception e) { + throw new NativeWindowException("EGLDisplayUtil.eglCreateEGLGraphicsDevice failed", e); + } + if( odev instanceof EGLGraphicsDevice ) { + device = (EGLGraphicsDevice)odev; + device.open(); + } else { + throw new NativeWindowException("EGLDisplayUtil.eglCreateEGLGraphicsDevice failed"); + } + } else { + device = new EGLGraphicsDevice(0, 0 /* EGL.EGL_NO_DISPLAY */, displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT, null); + } + return device; } else if( NativeWindowFactory.TYPE_AWT == nwt ) { throw new UnsupportedOperationException("n/a for windowing system: "+nwt); } else { @@ -712,7 +734,7 @@ public abstract class NativeWindowFactory { * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation * </p> */ - public static PointImmutable getLocationOnScreen(final NativeWindow nw) { + public static Point getLocationOnScreen(final NativeWindow nw) { final String nwt = NativeWindowFactory.getNativeWindowType(true); if( NativeWindowFactory.TYPE_X11 == nwt ) { return X11Lib.GetRelativeLocation(nw.getDisplayHandle(), nw.getScreenIndex(), nw.getWindowHandle(), 0, 0, 0); @@ -731,6 +753,4 @@ public abstract class NativeWindowFactory { } throw new UnsupportedOperationException("n/a for windowing system: "+nwt); } - - } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowHolder.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowHolder.java new file mode 100644 index 000000000..8cf9bcb1a --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowHolder.java @@ -0,0 +1,41 @@ +/** + * Copyright 2019 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.nativewindow; + +/** + * Accessor interface for implementing classes with ownership of a {@link NativeWindow} + * via an <i>is-a</i> or <i>has-a</i> relation. + */ +public interface NativeWindowHolder extends NativeSurfaceHolder { + /** + * Returns the associated {@link NativeWindow} of this {@link NativeWindowHolder}, which is identical to {@link #getNativeSurface()} + */ + public NativeWindow getNativeWindow(); +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java index cc70b6b7b..84fce7fc9 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java @@ -73,27 +73,6 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple } /** - * @deprecated Use {@link #create(GraphicsConfiguration, CapabilitiesImmutable, CapabilitiesImmutable)} - * Method constructs a new {@link AWTGraphicsConfiguration} primarily based - * on the given {@link Component}'s {@link GraphicsConfiguration}. - * @param awtComp the {@link Component}, which {@link GraphicsConfiguration} is used for the resulting {@link AWTGraphicsConfiguration} - * @param capsChosen if null, <code>capsRequested</code> is copied and aligned - * with the graphics {@link Capabilities} of the AWT Component to produce the chosen {@link Capabilities}. - * Otherwise the <code>capsChosen</code> is used. - * @param capsRequested if null, default {@link Capabilities} are used, otherwise the given values. - */ - public static AWTGraphicsConfiguration create(final Component awtComp, final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested) { - if(null==awtComp) { - throw new IllegalArgumentException("Null AWT Component"); - } - final GraphicsConfiguration gc = awtComp.getGraphicsConfiguration(); - if( null == gc ) { - throw new NativeWindowException("Null AWT GraphicsConfiguration @ "+awtComp); - } - return create(gc, capsChosen, capsRequested); - } - - /** * Method constructs a new {@link AWTGraphicsConfiguration} primarily based * on the given {@link GraphicsConfiguration}. * @param gc the {@link GraphicsConfiguration} for the resulting {@link AWTGraphicsConfiguration} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java index 2026ada0f..e5dcfa1c0 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java @@ -97,24 +97,23 @@ public class AppContextInfo { * The resulting thread name will have either '-OnAppContextTG' or '-OnSystemTG' appended * @return the {@link Thread} used to invoke the <code>runnable</code>, which may be the current {@link Thread} or a newly created one, see above. */ - public Thread invokeOnAppContextThread(final boolean waitUntilDone, final Runnable runnable, final String threadBaseName) { - final Thread t; + public RunnableTask invokeOnAppContextThread(final boolean waitUntilDone, final Runnable runnable, final String threadBaseName) { + final RunnableTask rt; if( update("invoke") ) { - t = Thread.currentThread(); + rt = RunnableTask.invokeOnCurrentThread(runnable); if( DEBUG ) { - System.err.println("Bug 1004: Invoke.0 on current AppContext thread: "+t+" "+toHexString(t.hashCode())); + System.err.println("Bug 1004: Invoke.0 on current AppContext: "+rt); } - runnable.run(); } else { final ThreadGroup tg = getCachedThreadGroup(); final String tName = threadBaseName + ( null != tg ? "-OnAppContextTG" : "-OnSystemTG" ); - t = RunnableTask.invokeOnNewThread(tg, waitUntilDone, runnable, tName); + rt = RunnableTask.invokeOnNewThread(tg, tName, waitUntilDone, runnable); if( DEBUG ) { final int tgHash = null != tg ? tg.hashCode() : 0; - System.err.println("Bug 1004: Invoke.1 on new AppContext thread: "+t+" "+toHexString(t.hashCode())+", tg "+tg+" "+toHexString(tgHash)); + System.err.println("Bug 1004: Invoke.1 on new AppContext: "+rt+", tg "+tg+" "+toHexString(tgHash)); } } - return t; + return rt; } /** diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 5d84325de..71a7602e6 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -120,7 +120,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, */ protected JAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { if (config == null) { - throw new NativeWindowException("Error: AbstractGraphicsConfiguration is null"); + throw new IllegalArgumentException("Error: AbstractGraphicsConfiguration is null"); } if(! ( config instanceof AWTGraphicsConfiguration ) ) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config); @@ -132,9 +132,13 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, this.awtConfig = (AWTGraphicsConfiguration) config; this.isApplet = false; this.offscreenSurfaceLayer = 0; + if(DEBUG) { + System.err.println(jawtStr2("ctor")); + } } private static String id(final Object obj) { return ( null!=obj ? toHexString(obj.hashCode()) : "nil" ); } - private String jawtStr() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; } + private String jawtStr1() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; } + private String jawtStr2(final String sub) { return jawtStr1()+"."+sub+" @ Thread "+getThreadName(); } private class JAWTComponentListener implements ComponentListener, HierarchyListener { private volatile boolean isShowing; @@ -180,7 +184,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, public void run() { isShowing = component.isShowing(); // Bug 1161: Runnable might be deferred, hence need to update if(DEBUG) { - System.err.println(jawtStr()+".attach @ Thread "+getThreadName()+": "+JAWTComponentListener.this.toString()); + System.err.println(jawtStr2("attach")+": "+JAWTComponentListener.this.toString()); } component.addComponentListener(JAWTComponentListener.this); component.addHierarchyListener(JAWTComponentListener.this); @@ -192,7 +196,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public void run() { if(DEBUG) { - System.err.println(jawtStr()+".detach @ Thread "+getThreadName()+": "+JAWTComponentListener.this.toString()); + System.err.println(jawtStr2("detach")+": "+JAWTComponentListener.this.toString()); } component.removeComponentListener(JAWTComponentListener.this); component.removeHierarchyListener(JAWTComponentListener.this); @@ -202,7 +206,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final void componentResized(final ComponentEvent e) { if(DEBUG) { - System.err.println(jawtStr()+".componentResized: "+s(e)); + System.err.println(jawtStr2("componentResized")+": "+s(e)); } layoutSurfaceLayerIfEnabled(isShowing); } @@ -210,7 +214,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final void componentMoved(final ComponentEvent e) { if(DEBUG) { - System.err.println(jawtStr()+".componentMoved: "+s(e)); + System.err.println(jawtStr2("componentMoved")+": "+s(e)); } layoutSurfaceLayerIfEnabled(isShowing); } @@ -218,7 +222,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final void componentShown(final ComponentEvent e) { if(DEBUG) { - System.err.println(jawtStr()+".componentShown: "+s(e)); + System.err.println(jawtStr2("componentShown")+": "+s(e)); } layoutSurfaceLayerIfEnabled(isShowing); } @@ -226,7 +230,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final void componentHidden(final ComponentEvent e) { if(DEBUG) { - System.err.println(jawtStr()+".componentHidden: "+s(e)); + System.err.println(jawtStr2("componentHidden")+": "+s(e)); } layoutSurfaceLayerIfEnabled(isShowing); } @@ -248,7 +252,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, final java.awt.Component changed = e.getChanged(); final boolean displayable = changed.isDisplayable(); final boolean showing = changed.isShowing(); - System.err.println(jawtStr()+".hierarchyChanged: action "+action+", displayable "+displayable+", showing [changed "+showing+", comp "+wasShowing+" -> "+isShowing+"], "+s(e)); + System.err.println(jawtStr2("hierarchyChanged")+": action "+action+", displayable "+displayable+", showing [changed "+showing+", comp "+wasShowing+" -> "+isShowing+"], "+s(e)); } } } @@ -257,7 +261,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected synchronized void invalidate() { if(DEBUG) { - System.err.println(jawtStr()+".invalidate() - "+jawtComponentListener.toString()); + System.err.println(jawtStr2("invalidate")+" - "+jawtComponentListener.toString()); if( isSurfaceLayerAttached() ) { System.err.println("OffscreenSurfaceLayer still attached: 0x"+Long.toHexString(offscreenSurfaceLayer)); } @@ -295,9 +299,12 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, */ public final void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config) { if(DEBUG) { - System.err.println(jawtStr()+".setAWTGraphicsConfiguration(): "+this.awtConfig+" -> "+config); + System.err.println(jawtStr2("setAWTGraphicsConfiguration")+": "+this.awtConfig+" -> "+config); // Thread.dumpStack(); } + if( null == awtConfig ) { + throw new IllegalArgumentException(jawtStr2("")+": null config"); + } this.awtConfig = config; } /** @@ -395,26 +402,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return hasPixelScaleChanged; } } - /** - * @deprecated Use {@link #updatePixelScale(GraphicsConfiguration, boolean)}. - */ - public final boolean updatePixelScale(final boolean clearFlag) { - return updatePixelScale(awtConfig.getAWTGraphicsConfiguration(), clearFlag); - } - - /** - * @deprecated Use {@link #updateLockedData(JAWT_Rectangle, GraphicsConfiguration)}. - */ - protected final boolean updateLockedData(final JAWT_Rectangle jawtBounds) { - throw new RuntimeException("Invalid API entry"); - } - /** - * @deprecated Use {@link #lockSurfaceImpl(GraphicsConfiguration)} - */ - protected int lockSurfaceImpl() throws NativeWindowException { - throw new RuntimeException("Invalid API entry"); - } - /** * Returns and clears the {@code hasPixelScaleChanged} flag, as set via {@link #lockSurface()}. @@ -771,6 +758,9 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, @Override public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + if( null == awtConfig ) { + throw new NativeWindowException(jawtStr2("")+": null awtConfig, invalidated"); + } return awtConfig.getNativeGraphicsConfiguration(); } @@ -826,7 +816,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, surfaceLock.lock(); try { if(DEBUG) { - System.err.println(jawtStr()+".destroy @ Thread "+getThreadName()); + System.err.println(jawtStr2("destroy")); } jawtComponentListener.detach(); invalidate(); @@ -930,7 +920,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, public String toString() { final StringBuilder sb = new StringBuilder(); - sb.append(jawtStr()+"["); + sb.append(jawtStr1()+"["); jawt2String(sb); sb.append( ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface+ ", attachedSurfaceLayer "+toHexString(getAttachedSurfaceLayer())+ diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java index 04d304cd5..320c0ec75 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java @@ -32,9 +32,11 @@ package com.jogamp.nativewindow.egl; -import com.jogamp.nativewindow.*; - import com.jogamp.common.util.VersionNumber; +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.DefaultGraphicsDevice; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.NativeWindowFactory; /** Encapsulates a graphics device on EGL platforms. */ @@ -73,11 +75,23 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl * This constructor exist to setup a default device connection/unit.<br> */ public EGLGraphicsDevice() { - super(NativeWindowFactory.TYPE_EGL, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + super(NativeWindowFactory.TYPE_EGL, DefaultGraphicsDevice.getDefaultDisplayConnection(), AbstractGraphicsDevice.DEFAULT_UNIT); this.nativeDisplayID[0] = 0 ; // EGL.EGL_DEFAULT_DISPLAY this.eglLifecycleCallback = null; } + public EGLGraphicsDevice(final AbstractGraphicsDevice aDevice, final long eglDisplay, final EGLDisplayLifecycleCallback eglLifecycleCallback) { + super(NativeWindowFactory.TYPE_EGL, aDevice.getConnection(), aDevice.getUnitID(), eglDisplay); + final long nativeDisplayID; + if( aDevice instanceof EGLGraphicsDevice ) { + nativeDisplayID = ((EGLGraphicsDevice)aDevice).getNativeDisplayID(); + } else { + nativeDisplayID = aDevice.getHandle(); + } + this.nativeDisplayID[0] = nativeDisplayID; + this.eglLifecycleCallback = eglLifecycleCallback; + } + public EGLGraphicsDevice(final long nativeDisplayID, final long eglDisplay, final String connection, final int unitID, final EGLDisplayLifecycleCallback eglLifecycleCallback) { super(NativeWindowFactory.TYPE_EGL, connection, unitID, eglDisplay); this.nativeDisplayID[0] = nativeDisplayID; diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java new file mode 100644 index 000000000..bffabdd5a --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java @@ -0,0 +1,291 @@ +/** + * Copyright 2019 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.nativewindow.javafx; + +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.VisualIDHolder; +import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; +import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptedRuntimeException; +import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.RunnableTask; +import com.sun.javafx.tk.TKStage; + +import javafx.application.Platform; +import javafx.stage.Window; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; + +public class JFXAccessor { + private static final boolean DEBUG; + + private static final boolean jfxAvailable; + private static final Method fxUserThreadGetter; + private static final Method tkStageGetter; + private static final Method glassWindowGetter; + private static final Method nativeWindowGetter; + + private static final String nwt; + private static final boolean isOSX; + private static final boolean isWindows; + private static final boolean isX11; + + static { + final boolean[] _DEBUG = new boolean[] { true }; + + final Method[] res = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { + @Override + public Method[] run() { + NativeWindowFactory.initSingleton(); // last resort .. + final Method[] res = new Method[] { null, null, null, null }; + try { + int i=0; + _DEBUG[0] = Debug.debug("JFX"); + /** + * com.sun.javafx.tk.Toolkit + */ + final Class<?> jfxToolkitClz = ReflectionUtil.getClass("com.sun.javafx.tk.Toolkit", false, JFXAccessor.class.getClassLoader()); + res[i] = jfxToolkitClz.getDeclaredMethod("getFxUserThread"); + res[i++].setAccessible(true); + + /*** + * class javafx.stage.Window + * class javafx.stage.Stage extends javafx.stage.Window + * class com.sun.javafx.tk.quantum.WindowStage extends com.sun.javafx.tk.quantum.GlassStage implements com.sun.javafx.tk.TKStage + * abstract com.sun.glass.ui.Window + * + * javafx.stage.Window: com.sun.javafx.tk.TKStage [impl_]getPeer() + * com.sun.javafx.tk.quantum.WindowStage: final com.sun.glass.ui.Window getPlatformWindow() + * com.sun.glass.ui.Window: public long getNativeWindow() + */ + final Class<?> jfxStageWindowClz = ReflectionUtil.getClass("javafx.stage.Window", false, JFXAccessor.class.getClassLoader()); + // final Class<?> jfxTkTKStageClz = ReflectionUtil.getClass("com.sun.javafx.tk.TKStage", false, JFXAccessor.class.getClassLoader()); + final Class<?> jfxTkQuWindowStageClz = ReflectionUtil.getClass("com.sun.javafx.tk.quantum.WindowStage", false, JFXAccessor.class.getClassLoader()); + final Class<?> jfxGlassUiWindowClz = ReflectionUtil.getClass("com.sun.glass.ui.Window", false, JFXAccessor.class.getClassLoader()); + + try { + // jfx 9, 11, 12, .. + res[i] = jfxStageWindowClz.getDeclaredMethod("getPeer"); + } catch (final NoSuchMethodException ex) { + // jfx 8 + res[i] = jfxStageWindowClz.getDeclaredMethod("impl_getPeer"); + } + res[i++].setAccessible(true); + + res[i] = jfxTkQuWindowStageClz.getDeclaredMethod("getPlatformWindow"); + res[i++].setAccessible(true); + res[i] = jfxGlassUiWindowClz.getDeclaredMethod("getNativeWindow"); + res[i++].setAccessible(true); + } catch (final Throwable t) { + if(_DEBUG[0]) { + ExceptionUtils.dumpThrowable("jfx-init", t); + } + } + return res; + } + }); + { + int i=0; + fxUserThreadGetter = res[i++]; + tkStageGetter = res[i++]; + glassWindowGetter = res[i++]; + nativeWindowGetter = res[i++]; + } + jfxAvailable = null != fxUserThreadGetter && null != tkStageGetter && null != glassWindowGetter && null != nativeWindowGetter; + + nwt = NativeWindowFactory.getNativeWindowType(false); + isOSX = NativeWindowFactory.TYPE_MACOSX == nwt; + isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt; + isX11 = NativeWindowFactory.TYPE_X11 == nwt; + + DEBUG = _DEBUG[0]; + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: JFXAccessor.<init> available "+jfxAvailable+", nwt "+nwt+"( x11 "+isX11+", win "+isWindows+", osx "+isOSX+")"); + } + } + + // + // Common any toolkit + // + + public static boolean isJFXAvailable() { return jfxAvailable; } + + /** + * Runs given {@code task} on the JFX Thread if it has not stopped and if caller is not already on the JFX Thread, + * otherwise execute given {@code task} on the current thread. + * @param wait + * @param task + * @see #isJFXThreadOrHasJFXThreadStopped() + */ + public static void runOnJFXThread(final boolean wait, final Runnable task) { + final Object rTaskLock = new Object(); + synchronized(rTaskLock) { // lock the task execution + if( isJFXThreadOrHasJFXThreadStopped() ) { + task.run(); + } else if( !wait ) { + Platform.runLater(task); + } else { + final RunnableTask rTask = new RunnableTask(task, + rTaskLock, + true /* always catch and report Exceptions, don't disturb EDT */, + null); + Platform.runLater(rTask); + try { + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rTask.getThrowable(); + if(null!=throwable) { + if(throwable instanceof NativeWindowException) { + throw (NativeWindowException)throwable; + } + throw new RuntimeException(throwable); + } + } + } + } + + public static Thread getJFXThread() throws NativeWindowException { + try { + return (Thread) fxUserThreadGetter.invoke(null); + } catch (final Throwable e) { + throw new NativeWindowException("Error getting JFX-Thread", e); + } + } + public static String getJFXThreadName() { + final Thread t = getJFXThread(); + return null != t ? t.getName() : null; + } + /** + * @return true if the JFX Thread has stopped + */ + public static boolean hasJFXThreadStopped() { + final Thread t = getJFXThread(); + return null == t || !t.isAlive(); + } + /** + * @return true if caller is on the JFX Thread + */ + public static boolean isJFXThread() { + final Thread t = getJFXThread(); + return Thread.currentThread() == t; + } + /** + * @return true if the JFX Thread has stopped or if caller is on the JFX Thread + */ + public static boolean isJFXThreadOrHasJFXThreadStopped() { + final Thread t = getJFXThread(); + return null == t || !t.isAlive() || Thread.currentThread() == t; + } + + /** + * @param stageWindow the JavaFX top heavyweight window handle + * @return the AbstractGraphicsDevice w/ the native device handle + * @throws NativeWindowException if an exception occurs retrieving the window handle or deriving the native device + * @throws UnsupportedOperationException if the windowing system is not supported + */ + public static AbstractGraphicsDevice getDevice(final Window stageWindow) throws NativeWindowException, UnsupportedOperationException { + if( isX11 ) { + // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering + final String connection = null; + final long x11DeviceHandle = X11Util.openDisplay(connection); + if( 0 == x11DeviceHandle ) { + throw new NativeWindowException("Error creating display: "+connection); + } + return new X11GraphicsDevice(x11DeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); + } + if( isWindows ) { + return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + } + if( isOSX ) { + return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + } + throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + } + + /** + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return + */ + public static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen) { + return NativeWindowFactory.createScreen(device, screen); + } + + public static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle) { + if( isX11 ) { + return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); + } + if( isWindows || isOSX ) { + return VisualIDHolder.VID_UNDEFINED; + } + throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + } + + /** + * @param stageWindow the JavaFX top heavyweight window handle + * @return the native window handle + * @throws NativeWindowException if an exception occurs retrieving the window handle + */ + public static long getWindowHandle(final Window stageWindow) throws NativeWindowException { + final long h[] = { 0 }; + runOnJFXThread(true, new Runnable() { + public void run() { + try { + final TKStage tkStage = (TKStage) tkStageGetter.invoke(stageWindow); + if( null != tkStage ) { + final Object platformWindow = glassWindowGetter.invoke(tkStage); + if( null != platformWindow ) { + final Object nativeHandle = nativeWindowGetter.invoke(platformWindow); + h[0] = ((Long) nativeHandle).longValue(); + } else if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: JFXAccessor null GlassWindow"); + } + } else if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: JFXAccessor null TKStage"); + } + } catch (final Throwable e) { + throw new NativeWindowException("Error getting Window handle", e); + } + } }); + return h[0]; + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java index 26a5f452b..6ddfc8950 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java @@ -387,7 +387,7 @@ public class SWTAccessor { return new X11GraphicsDevice(xdisplay0, AbstractGraphicsDevice.DEFAULT_UNIT, false /* owner */); } if( isWindows ) { - return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } if( isOSX ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java index fc5465bbf..aa511b625 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java @@ -120,6 +120,18 @@ public class Point implements Cloneable, PointImmutable { /** * Translate this instance's x- and y-components, + * i.e. add the values of the given delta point to them. + * @param pd delta point + * @return this instance for scaling + */ + public final Point translate(final PointImmutable pd) { + x += pd.getX() ; + y += pd.getY() ; + return this; + } + + /** + * Translate this instance's x- and y-components, * i.e. add the given deltas to them. * @param dx delta for x * @param dy delta for y diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java index 04619962d..bcb9741d6 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java @@ -33,10 +33,15 @@ package com.jogamp.nativewindow.x11; +import com.jogamp.common.util.Bitfield; import com.jogamp.nativewindow.CapabilitiesImmutable; import com.jogamp.nativewindow.MutableGraphicsConfiguration; +import jogamp.nativewindow.x11.X11Capabilities; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.XRenderDirectFormat; +import jogamp.nativewindow.x11.XRenderPictFormat; import jogamp.nativewindow.x11.XVisualInfo; /** Encapsulates a graphics configuration, or OpenGL pixel format, on @@ -48,6 +53,44 @@ import jogamp.nativewindow.x11.XVisualInfo; public class X11GraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { private XVisualInfo info; + // FBConfig + + protected static XRenderDirectFormat XVisual2XRenderMask(final long dpy, final long visual) { + final XRenderPictFormat xRenderPictFormat = XRenderPictFormat.create(); + return XVisual2XRenderMask(dpy, visual, xRenderPictFormat); + } + protected static XRenderDirectFormat XVisual2XRenderMask(final long dpy, final long visual, final XRenderPictFormat dest) { + if( !X11Lib.XRenderFindVisualFormat(dpy, visual, dest) ) { + return null; + } else { + return dest.getDirect(); + } + } + + public static X11Capabilities XVisualInfo2X11Capabilities(final X11GraphicsDevice device, final XVisualInfo info) { + final long display = device.getHandle(); + final X11Capabilities res = new X11Capabilities(info); + + final XRenderDirectFormat xrmask = ( null != info ) ? XVisual2XRenderMask( display, info.getVisual() ) : null ; + final int alphaMask = ( null != xrmask ) ? xrmask.getAlphaMask() : 0; + if( 0 < alphaMask ) { + res.setBackgroundOpaque(false); + res.setTransparentRedValue(xrmask.getRedMask()); + res.setTransparentGreenValue(xrmask.getGreenMask()); + res.setTransparentBlueValue(xrmask.getBlueMask()); + res.setTransparentAlphaValue(alphaMask); + } else { + res.setBackgroundOpaque(true); + } + // ALPHA shall be set at last - due to it's auto setting by the above (!opaque / samples) + res.setRedBits (Bitfield.Util.bitCount((int)info.getRed_mask())); + res.setGreenBits (Bitfield.Util.bitCount((int)info.getGreen_mask())); + res.setBlueBits (Bitfield.Util.bitCount((int)info.getBlue_mask())); + res.setAlphaBits (Bitfield.Util.bitCount(alphaMask)); + + return res; + } + public X11GraphicsConfiguration(final X11GraphicsScreen screen, final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, final XVisualInfo info) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/BcmVCArtifacts.java b/src/nativewindow/classes/jogamp/nativewindow/BcmVCArtifacts.java new file mode 100644 index 000000000..216c55a3a --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/BcmVCArtifacts.java @@ -0,0 +1,76 @@ +/** + * Copyright 2018 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.io.File; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Heuristics about Broadcom (BCM) VideoCore (VC) existence and usage + */ +public class BcmVCArtifacts { + static final boolean hasVCLib; + static final boolean hasVC4ModLocation; + static final boolean hasDriCard0File; + + static { + final File vcLibLocation = new File( + "/opt/vc/lib/libbcm_host.so"); + final File vc4ModLocation = new File( + "/sys/module/vc4"); + final File driCard0Location = new File( + "/dev/dri/card0"); + final boolean[] res = new boolean [3]; + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + res[0] = vcLibLocation.isFile(); + res[1] = vc4ModLocation.isDirectory(); + res[2] = driCard0Location.isFile(); + return null; + } } ); + hasVCLib = res[0]; + hasVC4ModLocation = res[1]; + hasDriCard0File = res[2]; + } + + /** + * @return True if proprietary BCM VC IV is probably being present + */ + public static final boolean guessVCIVPresent() { + return hasVCLib; + } + /** + * @return True if proprietary BCM VC IV is probably being used and not Xorg drivers + */ + public static final boolean guessVCIVUsed() { + return hasVCLib && !hasVC4ModLocation && !hasDriCard0File; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index 264bdf9d3..5a0c8a79a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -101,14 +101,15 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { @Override public void run() { + if( 0 != jawtSurfaceLayersHandle) { + // null rootSurfaceLayer OK + UnsetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer); + } + jawtSurfaceLayersHandle = 0; if( 0 != rootSurfaceLayer ) { - if( 0 != jawtSurfaceLayersHandle) { - UnsetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer); - } OSXUtil.DestroyCALayer(rootSurfaceLayer); rootSurfaceLayer = 0; } - jawtSurfaceLayersHandle = 0; } }); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 8ad089a56..f71dff1cb 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -34,6 +34,7 @@ import com.jogamp.nativewindow.util.Point; import com.jogamp.common.util.Function; import com.jogamp.common.util.FunctionTask; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.RunnableTask; import jogamp.nativewindow.Debug; @@ -267,22 +268,21 @@ public class OSXUtil implements ToolkitProperties { } else { // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, // otherwise we may freeze the OSX main thread. - Throwable throwable = null; final Object sync = new Object(); final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); synchronized(sync) { RunOnMainThread0(kickNSApp, rt); if( waitUntilDone ) { - try { - sync.wait(); - } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rt.getThrowable(); - } - if(null!=throwable) { - throw new RuntimeException(throwable); + while( rt.isInQueue() ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rt.getThrowable(); + if(null!=throwable) { + throw new RuntimeException(throwable); + } } } } @@ -341,23 +341,22 @@ public class OSXUtil implements ToolkitProperties { } else { // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, // otherwise we may freeze the OSX main thread. - Throwable throwable = null; final Object sync = new Object(); final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); synchronized(sync) { rt.setArgs(args); RunOnMainThread0(kickNSApp, rt); if( waitUntilDone ) { - try { - sync.wait(); - } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rt.getThrowable(); - } - if(null!=throwable) { - throw new RuntimeException(throwable); + while( rt.isInQueue() ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rt.getThrowable(); + if(null!=throwable) { + throw new RuntimeException(throwable); + } } } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java index bdf9630af..c0f277f09 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -32,6 +32,8 @@ import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.VersionNumber; import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.Debug; @@ -122,6 +124,107 @@ public class GDIUtil implements ToolkitProperties { return (Point) GetRelativeLocation0(src_win, dest_win, src_x, src_y); } + /** + * Windows >= 8, even if not manifested + * @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx + */ + public static final VersionNumber Win8Version = new VersionNumber(6, 2, 0); + + /** + * Windows >= 10, manifested + * @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx + */ + public static final VersionNumber Win10Version = new VersionNumber(10, 0, 0); + + /** + * Wrapper for {@link GDI#DwmIsCompositionEnabled()} + * taking the Windows 8 version into account. + * <p> + * If Windows version >= {@link #Win8Version} method always returns {@code true}, + * otherwise value of {@link GDI#DwmIsCompositionEnabled()} is returned. + * </p> + * @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa969518%28v=vs.85%29.aspx + */ + public static boolean DwmIsCompositionEnabled() { + final VersionNumber winVer = Platform.getOSVersionNumber(); + if( winVer.compareTo(Win8Version) >= 0 ) { + return true; + } else { + return GDI.DwmIsCompositionEnabled(); + } + } + + public static boolean DwmSetupTranslucency(final long hwnd, final boolean enable) { + if( !GDI.DwmIsExtensionAvailable() ) { + if(DEBUG) { + System.err.println("GDIUtil.DwmSetupTranslucency on wnd 0x"+Long.toHexString(hwnd)+": enable "+enable+" -> failed, extension not available"); + } + return !enable; + } + final VersionNumber winVer = Platform.getOSVersionNumber(); + final boolean isWin8 = winVer.compareTo(Win8Version) >= 0; + if( !isWin8 && !GDI.DwmIsCompositionEnabled() ) { + if(DEBUG) { + System.err.println("GDIUtil.DwmSetupTranslucency on wnd 0x"+Long.toHexString(hwnd)+": enable "+enable+" -> failed, composition disabled"); + } + return !enable; + } + final boolean hasWinCompEXT = GDI.IsWindowCompositionExtensionAvailable(); + final boolean useWinCompEXT = isWin8 && hasWinCompEXT; + final boolean isUndecorated = IsUndecorated(hwnd); + boolean ok; + if( useWinCompEXT && !isUndecorated ) { + final AccentPolicy accentPolicy = AccentPolicy.create(); + if( enable ) { + // For undecorated windows, this would also enable the Glass effect! + accentPolicy.setAccentState(GDI.ACCENT_ENABLE_BLURBEHIND); + } else { + accentPolicy.setAccentState(GDI.ACCENT_DISABLED); + } + ok = GDI.SetWindowCompositionAccentPolicy(hwnd, accentPolicy); + } else { + // Works even for >= Win8, if undecorated + final DWM_BLURBEHIND bb = DWM_BLURBEHIND.create(); + final int dwFlags = enable ? GDI.DWM_BB_ENABLE | GDI.DWM_BB_BLURREGION | GDI.DWM_BB_TRANSITIONONMAXIMIZED : GDI.DWM_BB_ENABLE; + // final int dwFlags = GDI.DWM_BB_ENABLE; + bb.setDwFlags( dwFlags ); + bb.setFEnable( enable ? 1 : 0 ); + bb.setHRgnBlur(0); + bb.setFTransitionOnMaximized(1); + ok = GDI.DwmEnableBlurBehindWindow(hwnd, bb); + if( ok ) { + final MARGINS m = MARGINS.create(); + m.setCxLeftWidth(-1); + m.setCxRightWidth(-1); + m.setCyBottomHeight(-1); + m.setCyTopHeight(-1); + ok = GDI.DwmExtendFrameIntoClientArea(hwnd, m); + } + } + /*** + * Not required .. + * + if( ok && isWin8 && !isUndecorated ) { + final IntBuffer pvAttribute = Buffers.newDirectIntBuffer(1); + if( enable ) { + // Glass Effect even if undecorated, hence not truly 100% translucent! + pvAttribute.put(0, GDI.DWMNCRP_ENABLED); + } else { + pvAttribute.put(0, GDI.DWMNCRP_DISABLED); + } + final int err = GDI.DwmSetWindowAttribute(hwnd, GDI.DWMWA_NCRENDERING_POLICY, + pvAttribute, + Buffers.sizeOfBufferElem(pvAttribute)*pvAttribute.capacity()); + ok = 0 == err; // S_OK + } */ + if(DEBUG) { + final boolean isChild = IsChild(hwnd); + System.err.println("GDIUtil.DwmSetupTranslucency on wnd 0x"+Long.toHexString(hwnd)+": enable "+enable+", isUndecorated "+isUndecorated+", isChild "+isChild+ + ", version "+winVer+", isWin8 "+isWin8+", hasWinCompEXT "+hasWinCompEXT+", useWinCompEXT "+useWinCompEXT+" -> ok: "+ok); + } + return ok; + } + public static boolean IsUndecorated(final long win) { return IsUndecorated0(win); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index f8a11f91e..4257376a0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -42,6 +42,7 @@ import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; import com.jogamp.nativewindow.x11.X11GraphicsConfiguration; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { @@ -59,15 +60,17 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor if(!(screen instanceof X11GraphicsScreen)) { throw new NativeWindowException("Only valid X11GraphicsScreen are allowed"); } - final X11Capabilities x11CapsChosen; + final XVisualInfo x11VisualInfo; if(VisualIDHolder.VID_UNDEFINED == nativeVisualID) { - x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, capsChosen)); + x11VisualInfo = getXVisualInfo(screen, capsChosen); } else { - x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, nativeVisualID)); + x11VisualInfo = getXVisualInfo(screen, nativeVisualID); } + + final X11Capabilities x11CapsChosen = X11GraphicsConfiguration.XVisualInfo2X11Capabilities((X11GraphicsDevice)screen.getDevice(), x11VisualInfo); final AbstractGraphicsConfiguration res = new X11GraphicsConfiguration((X11GraphicsScreen)screen, x11CapsChosen, capsRequested, x11CapsChosen.getXVisualInfo()); if(DEBUG) { - System.err.println("X11GraphicsConfigurationFactory.chooseGraphicsConfigurationImpl(visualID 0x"+Integer.toHexString(nativeVisualID)+", "+screen+","+capsChosen+"): "+res); + System.err.println("X11GraphicsConfigurationFactory.chooseGraphicsConfigurationImpl(visualID 0x"+Integer.toHexString(nativeVisualID)+", "+x11VisualInfo+", "+screen+","+capsChosen+"): "+res); } return res; } @@ -85,7 +88,6 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor if(xvis==null || num[0]<1) { return null; } - return XVisualInfo.create(xvis[0]); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index e59ff2ea8..6af5467f0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -463,10 +463,12 @@ public class X11Util implements ToolkitProperties { if(markAllDisplaysUnclosable) { namedDpy.setUncloseable(true); } - } - if(DEBUG) { - System.err.println("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); - // Thread.dumpStack(); + if(DEBUG) { + System.err.println("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+ + ". Open[reuseable "+reusableDisplayList.size()+", pending "+pendingDisplayList.size()+ + "]. Thread "+Thread.currentThread().getName()); + // Thread.dumpStack(); + } } return namedDpy.getHandle(); } diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 919108db9..c04ba786e 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -336,6 +336,7 @@ 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]; + [CATransaction begin]; NSRect rect = NSMakeRect(x, y, width, height); // Allocate the window @@ -365,6 +366,7 @@ NS_ENDHANDLER // [myView lockFocus]; // [myView unlockFocus]; + [CATransaction commit]; [pool release]; return (jlong) ((intptr_t) myWindow); @@ -379,9 +381,17 @@ 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); + [CATransaction begin]; +NS_DURING + NSWindow* mWin = (NSWindow*) ((intptr_t) nsWindow); [mWin close]; // performs release! +NS_HANDLER + // On killing or terminating the process [NSWindow _close], rarely + // throws an NSRangeException while ordering out menu items +NS_ENDHANDLER + + [CATransaction commit]; [pool release]; } @@ -861,8 +871,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Ge NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); return 0; } - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - return (jlong) ((intptr_t) surfaceLayers); + NSObject *surfaceLayersObj = (NSObject*) dsi->platformInfo; + [surfaceLayersObj retain]; // Pairs w/ Unset + DBG_PRINT("CALayer::GetJAWTSurfaceLayersHandle: surfaceLayers %p (refcnt %d)\n", surfaceLayersObj, (int)[surfaceLayersObj retainCount]); + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)surfaceLayersObj; + return (jlong) (intptr_t) surfaceLayers; } /* @@ -878,9 +892,11 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Set [CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + NSObject *surfaceLayersObj = (NSObject*) (intptr_t) jawtSurfaceLayersHandle; + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)surfaceLayersObj; MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: pre %p -> root %p (refcnt %d)\n", [surfaceLayers layer], layer, (int)[layer retainCount]); + [surfaceLayers setLayer: [layer retain]]; // Pairs w/ Unset [CATransaction commit]; @@ -902,20 +918,26 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_Uns [CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + NSObject *surfaceLayersObj = (NSObject*) (intptr_t) jawtSurfaceLayersHandle; + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)surfaceLayersObj; + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: surfaceLayers %p (refcnt %d)\n", surfaceLayersObj, (int)[surfaceLayersObj retainCount]); + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; - if(layer != [surfaceLayers layer]) { - NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); - return; + if(NULL != layer) { + if(layer != [surfaceLayers layer]) { + NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); + return; + } + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.1: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); + [layer release]; // Pairs w/ Set + [surfaceLayers setLayer: NULL]; // Pairs w/ Set } - DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); - [layer release]; // Pairs w/ Set - [surfaceLayers setLayer: NULL]; + [surfaceLayersObj release]; // Pairs w/ Get [CATransaction commit]; [pool release]; - DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X\n"); } @interface MainRunnable : NSObject diff --git a/src/nativewindow/native/win32/WindowsDWM.c b/src/nativewindow/native/win32/WindowsDWM.c index cc9ed6d8c..925ddd1d1 100644 --- a/src/nativewindow/native/win32/WindowsDWM.c +++ b/src/nativewindow/native/win32/WindowsDWM.c @@ -1,4 +1,5 @@ +#include <windows.h> #include "WindowsDWM.h" #include <stdlib.h> @@ -21,39 +22,68 @@ typedef HRESULT (WINAPI *DwmEnableCompositionPROCADDR)(UINT uCompositionAction); typedef HRESULT (WINAPI *DwmIsCompositionEnabledPROCADDR)(BOOL * pfEnabled); typedef HRESULT (WINAPI *DwmEnableBlurBehindWindowPROCADDR)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind); typedef HRESULT (WINAPI *DwmExtendFrameIntoClientAreaPROCADDR)(HWND hwnd, const MARGINS *pMarInset); +typedef HRESULT (WINAPI *DwmGetWindowAttributePROCADDR)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); +typedef HRESULT (WINAPI *DwmSetWindowAttributePROCADDR)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); +typedef BOOL (WINAPI *GetWindowCompositionAttributePROCADDR)(HWND hwnd, WINCOMPATTRDATA* pAttrData); +typedef BOOL (WINAPI *SetWindowCompositionAttributePROCADDR)(HWND hwnd, WINCOMPATTRDATA* pAttrData); -static int _init = 0; // 1: init, 2: has DWM extension +#define INIT_CALLED_MASK 1 << 0 +#define INIT_HAS_DWM_EXT_MASK 1 << 1 +#define INIT_HAS_WINCOMP_EXT_MASK 1 << 2 + +#define HAS_INIT(a) ( 0 != ( INIT_CALLED_MASK & (a) ) ) +#define HAS_DWM_EXT(a) ( 0 != ( INIT_HAS_DWM_EXT_MASK & (a) ) ) +#define HAS_WINCOMP_EXT(a) ( 0 != ( INIT_HAS_WINCOMP_EXT_MASK & (a) ) ) + +static int _init = 0; // INIT_ bits, see above static DwmEnableCompositionPROCADDR _DwmEnableComposition = NULL; static DwmIsCompositionEnabledPROCADDR _DwmIsCompositionEnabled = NULL; static DwmEnableBlurBehindWindowPROCADDR _DwmEnableBlurBehindWindow = NULL; static DwmExtendFrameIntoClientAreaPROCADDR _DwmExtendFrameIntoClientArea = NULL; +static DwmGetWindowAttributePROCADDR _DwmGetWindowAttribute = NULL; +static DwmSetWindowAttributePROCADDR _DwmSetWindowAttribute = NULL; +static GetWindowCompositionAttributePROCADDR _GetWindowCompositionAttribute = NULL; +static SetWindowCompositionAttributePROCADDR _SetWindowCompositionAttribute = NULL; static int initWindowsDWM() { - if(0 == _init) { - _init = 1; - HANDLE shell = LoadLibrary(TEXT("dwmapi.dll")); - if (shell) { - _DwmEnableComposition = (DwmEnableCompositionPROCADDR) GetProcAddressA (shell, "DwmEnableComposition"); - _DwmIsCompositionEnabled = (DwmIsCompositionEnabledPROCADDR) GetProcAddressA (shell, "DwmIsCompositionEnabled"); - _DwmEnableBlurBehindWindow = (DwmEnableBlurBehindWindowPROCADDR) GetProcAddressA (shell, "DwmEnableBlurBehindWindow"); - _DwmExtendFrameIntoClientArea = (DwmExtendFrameIntoClientAreaPROCADDR) GetProcAddressA (shell, "DwmExtendFrameIntoClientArea"); + if( !HAS_INIT(_init) ) { + _init |= INIT_CALLED_MASK; + HANDLE hDwmAPI = LoadLibrary(TEXT("dwmapi.dll")); + if (hDwmAPI) { + _DwmEnableComposition = (DwmEnableCompositionPROCADDR) GetProcAddressA (hDwmAPI, "DwmEnableComposition"); + _DwmIsCompositionEnabled = (DwmIsCompositionEnabledPROCADDR) GetProcAddressA (hDwmAPI, "DwmIsCompositionEnabled"); + _DwmEnableBlurBehindWindow = (DwmEnableBlurBehindWindowPROCADDR) GetProcAddressA (hDwmAPI, "DwmEnableBlurBehindWindow"); + _DwmExtendFrameIntoClientArea = (DwmExtendFrameIntoClientAreaPROCADDR) GetProcAddressA (hDwmAPI, "DwmExtendFrameIntoClientArea"); + _DwmGetWindowAttribute = (DwmGetWindowAttributePROCADDR) GetProcAddressA (hDwmAPI, "DwmGetWindowAttribute"); + _DwmSetWindowAttribute = (DwmSetWindowAttributePROCADDR) GetProcAddressA (hDwmAPI, "DwmSetWindowAttribute"); if(NULL != _DwmEnableComposition && NULL != _DwmIsCompositionEnabled && - NULL != _DwmEnableBlurBehindWindow && NULL != _DwmExtendFrameIntoClientArea) { - _init = 2; + NULL != _DwmEnableBlurBehindWindow && NULL != _DwmExtendFrameIntoClientArea && + NULL != _DwmGetWindowAttribute && NULL != _DwmSetWindowAttribute) { + _init |= INIT_HAS_DWM_EXT_MASK; + } + } + // FreeLibrary (hDwmAPI); + HANDLE hUser32 = LoadLibrary(TEXT("user32.dll")); + if (hUser32) { + _GetWindowCompositionAttribute = (GetWindowCompositionAttributePROCADDR) GetProcAddressA (hUser32, "GetWindowCompositionAttribute"); + _SetWindowCompositionAttribute = (SetWindowCompositionAttributePROCADDR) GetProcAddressA (hUser32, "SetWindowCompositionAttribute"); + if( NULL != _GetWindowCompositionAttribute && + NULL != _SetWindowCompositionAttribute ) { + _init |= INIT_HAS_WINCOMP_EXT_MASK; } } - // FreeLibrary (shell); - DBG_PRINT("DWM - initWindowsDWM: %d - s %p, e %p, c %p\n", _init, shell, _DwmEnableBlurBehindWindow, _DwmExtendFrameIntoClientArea); + // FreeLibrary (hUser32); + DBG_PRINT("DWM - initWindowsDWM: hasDWM %d, hasWinComp %d\n", HAS_DWM_EXT(_init), HAS_WINCOMP_EXT(_init)); } return _init; } BOOL DwmIsExtensionAvailable() { - return (2 == initWindowsDWM()) ? TRUE : FALSE; + return HAS_DWM_EXT( initWindowsDWM() ) ? TRUE : FALSE; } BOOL DwmIsCompositionEnabled( ) { - if(2 == initWindowsDWM()) { + if( HAS_DWM_EXT( initWindowsDWM() ) ) { BOOL fEnabled = FALSE; if( 0 == _DwmIsCompositionEnabled(&fEnabled) ) { DBG_PRINT("DWM - DwmIsCompositionEnabled: %d\n", fEnabled); @@ -65,14 +95,14 @@ BOOL DwmIsCompositionEnabled( ) { } BOOL DwmEnableComposition( UINT uCompositionAction ) { - if(2 == initWindowsDWM()) { + if( HAS_DWM_EXT( initWindowsDWM() ) ) { return 0 == _DwmEnableComposition(uCompositionAction) ? TRUE : FALSE; } return FALSE; } BOOL DwmEnableBlurBehindWindow(HWND hwnd, const DWM_BLURBEHIND* pBlurBehind) { - if(2 == initWindowsDWM()) { + if( HAS_DWM_EXT( initWindowsDWM() ) ) { _DwmEnableBlurBehindWindow(hwnd, pBlurBehind); DBG_PRINT("DWM - DwmEnableBlurBehindWindow: hwnd %p, f %d, on %d, %p\n", (void *)hwnd, @@ -86,10 +116,59 @@ BOOL DwmEnableBlurBehindWindow(HWND hwnd, const DWM_BLURBEHIND* pBlurBehind) { } BOOL DwmExtendFrameIntoClientArea(HWND hwnd, const MARGINS *pMarInset) { - if(2 == initWindowsDWM()) { + if( HAS_DWM_EXT( initWindowsDWM() ) ) { _DwmExtendFrameIntoClientArea(hwnd, pMarInset); return TRUE; } return FALSE; } +HRESULT DwmGetWindowAttribute(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute) { + if( HAS_DWM_EXT( initWindowsDWM() ) ) { + return _DwmGetWindowAttribute(hwnd, dwAttribute, pvAttribute, cbAttribute); + } + return E_NOINTERFACE; +} + +HRESULT DwmSetWindowAttribute(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) { + if( HAS_DWM_EXT( initWindowsDWM() ) ) { + return _DwmSetWindowAttribute(hwnd, dwAttribute, pvAttribute, cbAttribute); + } + return E_NOINTERFACE; +} + +BOOL IsWindowCompositionExtensionAvailable() { + return HAS_WINCOMP_EXT( initWindowsDWM() ) ? TRUE : FALSE; +} + +BOOL GetWindowCompositionAccentPolicy(HWND hwnd, AccentPolicy* pAccentPolicy) { + if( HAS_WINCOMP_EXT( initWindowsDWM() ) ) { + WINCOMPATTRDATA attrData = { WCA_ACCENT_POLICY, pAccentPolicy, sizeof(AccentPolicy) }; + return _GetWindowCompositionAttribute(hwnd, &attrData); + } + return FALSE; +} +BOOL SetWindowCompositionAccentPolicy(HWND hwnd, const AccentPolicy* pAccentPolicy) { + if( HAS_WINCOMP_EXT( initWindowsDWM() ) ) { + WINCOMPATTRDATA attrData = { WCA_ACCENT_POLICY, (AccentPolicy*)pAccentPolicy, sizeof(AccentPolicy) }; + return _SetWindowCompositionAttribute(hwnd, &attrData); + } + return FALSE; +} + +#if 0 +BOOL GetWindowCompositionAttribute(HWND hwnd, WINCOMPATTRDATA* pAttrData) { + if( HAS_WINCOMP_EXT( initWindowsDWM() ) ) { + return _GetWindowCompositionAttribute(hwnd, pAttrData); + } + return FALSE; +} + +BOOL SetWindowCompositionAttribute(HWND hwnd, WINCOMPATTRDATA* pAttrData) { + if( HAS_WINCOMP_EXT( initWindowsDWM() ) ) { + return _SetWindowCompositionAttribute(hwnd, pAttrData); + } + return FALSE; +} +#endif + diff --git a/src/nativewindow/native/win32/WindowsDWM.h b/src/nativewindow/native/win32/WindowsDWM.h deleted file mode 100644 index 6e5160fa4..000000000 --- a/src/nativewindow/native/win32/WindowsDWM.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _WINDOWS_DWM_H_ -#define _WINDOWS_DWM_H_ - - #include <windows.h> - - #define DWM_BB_ENABLE 0x00000001 // fEnable has been specified - #define DWM_BB_BLURREGION 0x00000002 - #define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 - #define DWM_EC_DISABLECOMPOSITION 0 - #define DWM_EC_ENABLECOMPOSITION 1 - - typedef struct _DWM_BLURBEHIND - { - DWORD dwFlags; - BOOL fEnable; - HRGN hRgnBlur; - BOOL fTransitionOnMaximized; - } DWM_BLURBEHIND, *PDWM_BLURBEHIND; - - typedef struct _MARGINS - { - int cxLeftWidth; // width of left border that retains its size - int cxRightWidth; // width of right border that retains its size - int cyTopHeight; // height of top border that retains its size - int cyBottomHeight; // height of bottom border that retains its size - } MARGINS, *PMARGINS; - - BOOL DwmIsExtensionAvailable(); - BOOL DwmIsCompositionEnabled(); - BOOL DwmEnableComposition( UINT uCompositionAction ); - BOOL DwmEnableBlurBehindWindow(HWND hwnd, const DWM_BLURBEHIND* pBlurBehind); - BOOL DwmExtendFrameIntoClientArea(HWND hwnd, const MARGINS *pMarInset); - -#endif /* _WINDOWS_DWM_H_ */ diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index 2ed2194d8..dd15eb3ea 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -59,6 +59,7 @@ public class NewtFactory { public static final String DRIVER_DEFAULT_ROOT_PACKAGE = "jogamp.newt.driver"; private static IOUtil.ClassResources defaultWindowIcons; + private static String sysPaths = "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"; static { AccessController.doPrivileged(new PrivilegedAction<Object>() { @@ -67,12 +68,11 @@ public class NewtFactory { NativeWindowFactory.initSingleton(); // last resort .. { /** See API Doc in {@link Window} ! */ - final String[] paths = PropertyAccess.getProperty("newt.window.icons", true, "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png").split("\\s"); + final String[] paths = PropertyAccess.getProperty("newt.window.icons", true, sysPaths).split("[\\s,]"); if( paths.length < 2 ) { throw new IllegalArgumentException("Property 'newt.window.icons' did not specify at least two PNG icons, but "+Arrays.toString(paths)); } - final Class<?> clazz = NewtFactory.class; - defaultWindowIcons = new IOUtil.ClassResources(clazz, paths); + defaultWindowIcons = new IOUtil.ClassResources(paths, NewtFactory.class.getClassLoader(), null); } return null; } } ); @@ -81,7 +81,7 @@ public class NewtFactory { /** * Returns the application window icon resources to be used. * <p> - * Property <code>newt.window.icons</code> may define a list of PNG icons separated by a whitespace character. + * Property <code>newt.window.icons</code> may define a list of PNG icons separated by one whitespace or one comma character. * Shall reference at least two PNG icons, from lower (16x16) to higher (>= 32x32) resolution. * </p> * <p> diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 37147d1ca..30b02cb61 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -83,16 +83,22 @@ import com.jogamp.nativewindow.util.SurfaceSize; * <a name="customwindowicons"><h5>Custom Window Icons</h5></a> * <p> * Custom window icons can be defined via system property <code>newt.window.icons</code>, - * which shall contain a space separated list of PNG icon locations from low- to high-resolution. + * which shall contain a list of PNG icon locations from low- to high-resolution, + * separated by one whitespace or one comma character. * The location must be resolvable via classpath, i.e. shall reference a location within the jar file. * Example (our default): * <pre> - * -Dnewt.window.icons="newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png" - * -Djnlp.newt.window.icons="newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png" + * -Dnewt.window.icons="newt/data/jogamp-16x16.png,newt/data/jogamp-32x32.png" + * -Djnlp.newt.window.icons="newt/data/jogamp-16x16.png,newt/data/jogamp-32x32.png" * </pre> * The property can also be set programmatically, which must happen before any NEWT classes are <i>touched</i>: * <pre> - * System.setProperty("newt.window.icons", "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"); + * System.setProperty("newt.window.icons", "newt/data/jogamp-16x16.png, newt/data/jogamp-32x32.png"); + * </pre> + * To disable even Jogamp's own window icons in favor of system icons, + * simply set a non-existing location, e.g.: + * <pre> + * -Dnewt.window.icons="null,null" * </pre> * </p> * @@ -125,6 +131,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_VISIBLE = 0; // reconfig-flag /** @@ -134,6 +141,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code true}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_AUTOPOSITION = 1; /** @@ -145,6 +153,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_CHILDWIN = 2; // reconfig-flag /** @@ -152,6 +161,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_FOCUSED = 3; /** @@ -159,6 +169,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_UNDECORATED = 4; // reconfig-flag /** @@ -166,6 +177,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_ALWAYSONTOP = 5; // reconfig-flag /** @@ -173,6 +185,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_ALWAYSONBOTTOM = 6; // reconfig-flag /** @@ -180,6 +193,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_STICKY = 7; // reconfig-flag /** @@ -187,6 +201,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code true}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_RESIZABLE = 8; // reconfig-flag /** @@ -194,6 +209,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_MAXIMIZED_VERT = 9; // reconfig-flag /** @@ -201,77 +217,127 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_MAXIMIZED_HORZ = 10; // reconfig-flag /** * Set if window is in <i>fullscreen mode</i>, otherwise cleared. + * <p> + * Usually fullscreen mode implies {@link #STATE_BIT_UNDECORATED}, + * however, an implementation is allowed to ignore this if unavailable. + * </p> * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ public static final int STATE_BIT_FULLSCREEN = 11; // reconfig-flag - // Hidden in WindowImpl: - // static final int STATE_BIT_FULLSCREEN_SPAN = 12; - /** * Set if the <i>pointer is visible</i> when inside the window, otherwise cleared. * <p>Bit number {@value}.</p> * <p>Defaults to {@code true}.</p> * @see #getStateMask() + * @since 2.3.2 */ - public static final int STATE_BIT_POINTERVISIBLE = 13; + public static final int STATE_BIT_POINTERVISIBLE = 12; /** * Set if the <i>pointer is confined</i> to the window, otherwise cleared. * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ - public static final int STATE_BIT_POINTERCONFINED = 14; + public static final int STATE_BIT_POINTERCONFINED = 13; - /** Bitmask for {@link #STATE_BIT_VISIBLE}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_VISIBLE}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_VISIBLE = 1 << STATE_BIT_VISIBLE; - /** Bitmask for {@link #STATE_BIT_AUTOPOSITION}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_AUTOPOSITION}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_AUTOPOSITION = 1 << STATE_BIT_AUTOPOSITION; - /** Bitmask for {@link #STATE_BIT_CHILDWIN}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_CHILDWIN}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_CHILDWIN = 1 << STATE_BIT_CHILDWIN; - /** Bitmask for {@link #STATE_BIT_FOCUSED}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_FOCUSED}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_FOCUSED = 1 << STATE_BIT_FOCUSED; - /** Bitmask for {@link #STATE_BIT_UNDECORATED}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_UNDECORATED}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_UNDECORATED = 1 << STATE_BIT_UNDECORATED; - /** Bitmask for {@link #STATE_BIT_ALWAYSONTOP}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_ALWAYSONTOP}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_ALWAYSONTOP = 1 << STATE_BIT_ALWAYSONTOP; - /** Bitmask for {@link #STATE_BIT_ALWAYSONBOTTOM}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_ALWAYSONBOTTOM}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_ALWAYSONBOTTOM = 1 << STATE_BIT_ALWAYSONBOTTOM; - /** Bitmask for {@link #STATE_BIT_STICKY}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_STICKY}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_STICKY = 1 << STATE_BIT_STICKY; - /** Bitmask for {@link #STATE_BIT_RESIZABLE}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_RESIZABLE}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_RESIZABLE = 1 << STATE_BIT_RESIZABLE; - /** Bitmask for {@link #STATE_BIT_MAXIMIZED_VERT}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_MAXIMIZED_VERT}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_MAXIMIZED_VERT = 1 << STATE_BIT_MAXIMIZED_VERT; - /** Bitmask for {@link #STATE_BIT_MAXIMIZED_HORZ}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_MAXIMIZED_HORZ}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_MAXIMIZED_HORZ = 1 << STATE_BIT_MAXIMIZED_HORZ; - /** Bitmask for {@link #STATE_BIT_FULLSCREEN}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_FULLSCREEN}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_FULLSCREEN = 1 << STATE_BIT_FULLSCREEN; - /** Bitmask for {@link #STATE_BIT_POINTERVISIBLE}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_POINTERVISIBLE}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_POINTERVISIBLE = 1 << STATE_BIT_POINTERVISIBLE; - /** Bitmask for {@link #STATE_BIT_POINTERCONFINED}, {@value}. */ + /** + * Bitmask for {@link #STATE_BIT_POINTERCONFINED}, {@value}. + * @since 2.3.2 + */ public static final int STATE_MASK_POINTERCONFINED = 1 << STATE_BIT_POINTERCONFINED; /** * Number of all public state bits. * @see #getStateMask() + * @since 2.3.2 */ public int getStatePublicBitCount(); /** * Bitmask covering all public state bits. * @see #getStateMask() + * @since 2.3.2 */ public int getStatePublicBitmask(); /** * Returns the current status mask of this instance. + * @see #getSupportedStateMask() * @see #STATE_MASK_VISIBLE * @see #STATE_MASK_AUTOPOSITION * @see #STATE_MASK_CHILDWIN @@ -286,14 +352,62 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * @see #STATE_MASK_FULLSCREEN * @see #STATE_MASK_POINTERVISIBLE * @see #STATE_MASK_POINTERCONFINED + * @since 2.3.2 */ int getStateMask(); /** * Returns a string representation of the {@link #getStateMask() current state mask}. + * @since 2.3.2 */ String getStateMaskString(); + /** + * Returns the supported {@link #getStateMask() state mask} of the implementation. + * <p> + * Implementation provides supported {@link #getStateMask() state mask} values at runtime + * <i>after</i> native window creation, i.e. first visibility. + * </p> + * <p> + * Please note that a window's size shall also be allowed to change, i.e. {@link #setSize(int, int)}. + * </p> + * <p> + * Default value is {@link #STATE_MASK_VISIBLE} | {@link #STATE_MASK_FOCUSED} | {@link #STATE_MASK_FULLSCREEN}, + * i.e. the <b>minimum requirement</b> for all implementations. + * </p> + * <p> + * Before native window creation {@link #getStatePublicBitmask()} is returned, + * i.e. it is assumed all features are supported. + * </p> + * <p> + * Semantic of the supported state-mask bits (after native creation, i.e. 1st visibility): + * <ul> + * <li>{@link #STATE_MASK_VISIBLE}: {@link #setVisible(boolean) Visibility} can be toggled. <b>Minimum requirement</b>.</li> + * <li>{@link #STATE_MASK_CHILDWIN}: {@link #reparentWindow(NativeWindow, int, int, int) Native window parenting} is supported.</li> + * <li>{@link #STATE_MASK_FOCUSED}: Window {@link #requestFocus() focus management} is supported. <b>Minimum requirement</b>.</li> + * <li>{@link #STATE_MASK_UNDECORATED}: {@link #setUndecorated(boolean) Window decoration} can be toggled.</li> + * <li>{@link #STATE_MASK_ALWAYSONTOP}: Window can be set {@link #setAlwaysOnTop(boolean) always-on-top}. </li> + * <li>{@link #STATE_MASK_ALWAYSONBOTTOM}: Window can be set {@link #setAlwaysOnBottom(boolean) always-on-bottom}. </li> + * <li>{@link #STATE_MASK_STICKY}: Window can be set {@link #setSticky(boolean) sticky}.</li> + * <li>{@link #STATE_MASK_RESIZABLE}: Window {@link #setResizable(boolean) resizability} can be toggled.</li> + * <li>{@link #STATE_MASK_MAXIMIZED_VERT}: Window can be {@link #setMaximized(boolean, boolean) maximized-vertically}. </li> + * <li>{@link #STATE_MASK_MAXIMIZED_HORZ}: Window can be {@link #setMaximized(boolean, boolean) maximized-horizontally}. </li> + * <li>{@link #STATE_MASK_FULLSCREEN}: Window {@link #setFullscreen(boolean) fullscreen} can be toggled. </li> + * <li>{@link #STATE_MASK_POINTERVISIBLE}: Window {@link #setPointerVisible(boolean) pointer visibility} can be toggled. </li> + * <li>{@link #STATE_MASK_POINTERCONFINED}: Window {@link #confinePointer(boolean) pointer can be confined}. </li> + * </ul> + * </p> + * @see #getStateMask() + * @since 2.3.2 + */ + int getSupportedStateMask(); + + /** + * Returns a string representation of the {@link #getSupportedStateMask() supported state mask}. + * @since 2.3.2 + */ + String getSupportedStateMaskString(); + // // Lifecycle // @@ -598,11 +712,13 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Operation is ignored if this instance {@link #isChildWindow() is a child window}.</p> * @see {@link #STATE_BIT_ALWAYSONBOTTOM} * @see {@link #STATE_MASK_ALWAYSONBOTTOM} + * @since 2.3.2 */ void setAlwaysOnBottom(boolean value); /** * @see {@link #STATE_BIT_ALWAYSONBOTTOM} * @see {@link #STATE_MASK_ALWAYSONBOTTOM} + * @since 2.3.2 */ boolean isAlwaysOnBottom(); @@ -610,11 +726,13 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Operation is ignored if this instance {@link #isChildWindow() is a child window}.</p> * @see {@link #STATE_BIT_RESIZABLE} * @see {@link #STATE_MASK_RESIZABLE} + * @since 2.3.2 */ void setResizable(final boolean value); /** * @see {@link #STATE_BIT_RESIZABLE} * @see {@link #STATE_MASK_RESIZABLE} + * @since 2.3.2 */ boolean isResizable(); @@ -622,31 +740,35 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p>Operation is ignored if this instance {@link #isChildWindow() is a child window}.</p> * @see {@link #STATE_BIT_STICKY} * @see {@link #STATE_MASK_STICKY} + * @since 2.3.2 */ void setSticky(final boolean value); /** * @see {@link #STATE_BIT_STICKY} * @see {@link #STATE_MASK_STICKY} + * @since 2.3.2 */ boolean isSticky(); /** - * <p>Operation is ignored in {@link #isFullscreen() fullscreen mode}.</p> * <p>Operation is ignored if this instance {@link #isChildWindow() is a child window}.</p> * @see {@link #STATE_BIT_MAXIMIZED_HORZ} * @see {@link #STATE_BIT_MAXIMIZED_VERT} * @see {@link #STATE_MASK_MAXIMIZED_HORZ} * @see {@link #STATE_MASK_MAXIMIZED_VERT} + * @since 2.3.2 */ void setMaximized(final boolean horz, final boolean vert); /** * @see {@link #STATE_BIT_MAXIMIZED_VERT} * @see {@link #STATE_MASK_MAXIMIZED_VERT} + * @since 2.3.2 */ boolean isMaximizedVert(); /** * @see {@link #STATE_BIT_MAXIMIZED_HORZ} * @see {@link #STATE_MASK_MAXIMIZED_HORZ} + * @since 2.3.2 */ boolean isMaximizedHorz(); diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index ae32fd164..a0083b4ea 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -49,7 +49,9 @@ import java.security.PrivilegedAction; import java.util.Set; import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowHolder; import com.jogamp.nativewindow.OffscreenLayerOption; import com.jogamp.nativewindow.WindowClosingProtocol; import com.jogamp.opengl.GLAnimatorControl; @@ -100,7 +102,7 @@ import com.jogamp.opengl.util.TileRenderer; * the underlying JAWT mechanism to composite the image, if supported. */ @SuppressWarnings("serial") -public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol, OffscreenLayerOption, AWTPrintLifecycle { +public class NewtCanvasAWT extends java.awt.Canvas implements NativeWindowHolder, WindowClosingProtocol, OffscreenLayerOption, AWTPrintLifecycle { public static final boolean DEBUG = Debug.debug("Window"); private final Object sync = new Object(); @@ -110,7 +112,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto private Window newtChild = null; private boolean newtChildAttached = false; private boolean isOnscreen = true; - private WindowClosingMode newtChildCloseOp; + private WindowClosingMode newtChildCloseOp = WindowClosingMode.DISPOSE_ON_CLOSE; private final AWTParentWindowAdapter awtWinAdapter; private final AWTAdapter awtMouseAdapter; private final AWTAdapter awtKeyAdapter; @@ -420,10 +422,22 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto return newtChild; } - /** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called, - * or {@link #addNotify()} hasn't been called yet.*/ + /** + * {@inheritDoc} + * @return this AWT Canvas {@link NativeWindow} representation, may be null in case {@link #removeNotify()} has been called, + * or {@link #addNotify()} hasn't been called yet. + */ + @Override public NativeWindow getNativeWindow() { return jawtWindow; } + /** + * {@inheritDoc} + * @return this AWT Canvas {@link NativeSurface} representation, may be null in case {@link #removeNotify()} has been called, + * or {@link #addNotify()} hasn't been called yet. + */ + @Override + public NativeSurface getNativeSurface() { return jawtWindow; } + @Override public WindowClosingMode getDefaultCloseOperation() { return awtWindowClosingProtocol.getDefaultCloseOperation(); 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 cd53294a1..6bf9f41a6 100644 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java @@ -115,7 +115,7 @@ public class JOGLNewtApplet1Run extends Applet { String glEventListenerClazzName=null; String glProfileName=null; - int glSwapInterval=0; + int glSwapInterval=1; boolean glDebug=false; boolean glTrace=false; boolean glUndecorated=false; diff --git a/src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java b/src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java new file mode 100644 index 000000000..e04ed326d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java @@ -0,0 +1,670 @@ +/** + * Copyright 2019 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.javafx; + +import com.jogamp.common.util.PropertyAccess; +import com.jogamp.nativewindow.AbstractGraphicsConfiguration; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.Capabilities; +import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.GraphicsConfigurationFactory; +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.NativeWindowHolder; +import com.jogamp.nativewindow.SurfaceUpdatedListener; +import com.jogamp.nativewindow.WindowClosingProtocol; +import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode; +import com.jogamp.nativewindow.util.Insets; +import com.jogamp.nativewindow.util.InsetsImmutable; +import com.jogamp.nativewindow.util.Point; +import com.jogamp.nativewindow.util.Rectangle; +import com.jogamp.opengl.GLCapabilities; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.EventHandler; +import javafx.geometry.Bounds; +import javafx.scene.Scene; +import javafx.scene.canvas.Canvas; +import jogamp.newt.Debug; +import jogamp.newt.javafx.JFXEDTUtil; + +import com.jogamp.nativewindow.javafx.JFXAccessor; +import com.jogamp.newt.Display; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.util.EDTUtil; + +/** + * A NEWT based JFX {@link Canvas} specialization allowing a NEWT child {@link Window} to be attached using native parenting. + * <p> + * {@link NewtCanvasJFX} allows utilizing custom {@link GLCapabilities} settings independent from the JavaFX's window + * as well as independent rendering from JavaFX's thread. + * </p> + * <p> + * {@link NewtCanvasJFX} allows native parenting operations before and after + * it's belonging Group's Scene has been attached to the JavaFX {@link javafx.stage.Window Window}'s actual native window, + * i.e. becoming fully realized and visible. + * </p> + * <p> + * Note that {@link JFXAccessor#runOnJFXThread(boolean, Runnable)} is still used to for certain + * mandatory JavaFX lifecycle operation on the JavaFX thread. + * </p> + */ +public class NewtCanvasJFX extends Canvas implements NativeWindowHolder, WindowClosingProtocol { + private static final boolean DEBUG = Debug.debug("Window"); + private static final boolean USE_JFX_EDT = PropertyAccess.getBooleanProperty("jogamp.newt.javafx.UseJFXEDT", true, true); + private volatile javafx.stage.Window parentWindow = null; + private volatile AbstractGraphicsScreen screen = null; + + private WindowClosingMode newtChildClosingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private WindowClosingMode closingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private final Rectangle clientArea = new Rectangle(); + + private volatile JFXNativeWindow nativeWindow = null; + private volatile Window newtChild = null; + private volatile boolean newtChildReady = false; // ready if JFXEDTUtil is set and newtChild parented + private volatile boolean postSetSize = false; // pending resize + private volatile boolean postSetPos = false; // pending pos + + private final EventHandler<javafx.stage.WindowEvent> windowClosingListener = new EventHandler<javafx.stage.WindowEvent>() { + public final void handle(final javafx.stage.WindowEvent e) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.DISPOSE, "+e+", closeOp "+closingMode); + } + if( WindowClosingMode.DISPOSE_ON_CLOSE == closingMode ) { + NewtCanvasJFX.this.destroy(); + } else { + // avoid JavaFX closing operation + e.consume(); + } + } }; + private final EventHandler<javafx.stage.WindowEvent> windowShownListener = new EventHandler<javafx.stage.WindowEvent>() { + public final void handle(final javafx.stage.WindowEvent e) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.SHOWN, "+e); + } + repaintAction(true); + } }; + + /** + * Instantiates a NewtCanvas with a NEWT child. + * + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an JFX conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * @param child optional preassigned {@link #Window}, maybe null + */ + public NewtCanvasJFX(final Window child) { + super(); + + updateParentWindowAndScreen(); + + final ChangeListener<Number> sizeListener = new ChangeListener<Number>() { + @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Size, "+oldValue.doubleValue()+" -> "+newValue.doubleValue()+", has "+getWidth()+"x"+getHeight()); + } + updateSizeCheck((int)getWidth(), (int)getHeight()); + repaintAction(isVisible()); + } }; + this.widthProperty().addListener(sizeListener); + this.heightProperty().addListener(sizeListener); + this.visibleProperty().addListener(new ChangeListener<Boolean>() { + @Override public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue, final Boolean newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Visible, "+oldValue.booleanValue()+" -> "+newValue.booleanValue()+", has "+isVisible()); + } + repaintAction(newValue.booleanValue()); + } + }); + this.sceneProperty().addListener(new ChangeListener<Scene>() { + @Override public void changed(final ObservableValue<? extends Scene> observable, final Scene oldValue, final Scene newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Scene, "+oldValue+" -> "+newValue+", has "+getScene()); + if(null != newValue) { + final javafx.stage.Window w = newValue.getWindow(); + System.err.println("NewtCanvasJFX.Event.Scene window "+w+" (showing "+(null!=w?w.isShowing():0)+")"); + } + } + if( updateParentWindowAndScreen() ) { + repaintAction(isVisible()); + } + } + }); + + if(null != child) { + setNEWTChild(child); + } + } + + private final void repaintAction(final boolean visible) { + if( visible && ( null != nativeWindow || validateNative(true /* completeReparent */) ) ) { + if( newtChildReady ) { + if( postSetSize ) { + newtChild.setSize(clientArea.getWidth(), clientArea.getHeight()); + postSetSize = false; + } + if( postSetPos ) { + newtChild.setPosition(clientArea.getX(), clientArea.getY()); + postSetPos = false; + } + newtChild.windowRepaint(0, 0, clientArea.getWidth(), clientArea.getHeight()); + } + } + } + + private final void updatePosSizeCheck() { + final Bounds b = localToScene(getBoundsInLocal()); + updatePosCheck((int)b.getMinX(), (int)b.getMinY()); + updateSizeCheck((int)getWidth(), (int)getHeight()); + } + private final void updatePosCheck(final int newX, final int newY) { + final boolean posChanged; + { + final Rectangle oClientArea = clientArea; + posChanged = newX != oClientArea.getX() || newY != oClientArea.getY(); + if( posChanged ) { + clientArea.setX(newX); + clientArea.setY(newY); + } + } + if(DEBUG) { + final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; + System.err.println("NewtCanvasJFX.updatePosCheck: posChanged "+posChanged+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+clientArea.getX()+"/"+clientArea.getY()+" "+clientArea.getWidth()+"x"+clientArea.getHeight()+" - surfaceHandle 0x"+Long.toHexString(nsh)); + } + if( posChanged ) { + if( newtChildReady ) { + newtChild.setPosition(clientArea.getX(), clientArea.getY()); + } else { + postSetPos = true; + } + } + } + private final void updateSizeCheck(final int newWidth, final int newHeight) { + final boolean sizeChanged; + { + final Rectangle oClientArea = clientArea; + sizeChanged = newWidth != oClientArea.getWidth() || newHeight != oClientArea.getHeight(); + if( sizeChanged ) { + clientArea.setWidth(newWidth); + clientArea.setHeight(newHeight); + } + } + if(DEBUG) { + final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; + System.err.println("NewtCanvasJFX.updateSizeCheck: sizeChanged "+sizeChanged+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+clientArea.getX()+"/"+clientArea.getY()+" "+clientArea.getWidth()+"x"+clientArea.getHeight()+" - surfaceHandle 0x"+Long.toHexString(nsh)); + } + if( sizeChanged ) { + if( newtChildReady ) { + newtChild.setSize(clientArea.getWidth(), clientArea.getHeight()); + } else { + postSetSize = true; + } + } + } + + private final ChangeListener<javafx.stage.Window> sceneWindowChangeListener = new ChangeListener<javafx.stage.Window>() { + @Override public void changed(final ObservableValue<? extends javafx.stage.Window> observable, final javafx.stage.Window oldValue, final javafx.stage.Window newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Window, "+oldValue+" -> "+newValue); + } + if( updateParentWindowAndScreen() ) { + repaintAction(isVisible()); + } + } }; + + private boolean updateParentWindowAndScreen() { + final Scene s = this.getScene(); + if( null != s ) { + final javafx.stage.Window w = s.getWindow(); + if( DEBUG ) { + System.err.println("NewtCanvasJFX.updateParentWindowAndScreen: Scene "+s+", Window "+w+" (showing "+(null!=w?w.isShowing():0)+")"); + } + if( w != parentWindow ) { + destroyImpl(false); + } + parentWindow = w; + if( null != w ) { + screen = JFXAccessor.getScreen(JFXAccessor.getDevice(parentWindow), -1 /* default */); + parentWindow.addEventHandler(javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST, windowClosingListener); + parentWindow.addEventHandler(javafx.stage.WindowEvent.WINDOW_SHOWN, windowShownListener); + return true; + } else { + s.windowProperty().addListener(sceneWindowChangeListener); + } + } else { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.updateParentWindowAndScreen: Null Scene"); + } + if( null != parentWindow ) { + destroyImpl(false); + } + } + return false; + } + + /** + * Destroys this resource: + * <ul> + * <li> Make the NEWT Child invisible </li> + * <li> Disconnects the NEWT Child from this Canvas NativeWindow, reparent to NULL </li> + * <li> Issues {@link Window#destroy()} on the NEWT Child</li> + * <li> Remove reference to the NEWT Child</li> + * </ul> + * JavaFX will issue this call when sending out the {@link javafx.stage.WindowEvent#WINDOW_CLOSE_REQUEST} automatically, + * if the user has not overridden the default {@link WindowClosingMode#DISPOSE_ON_CLOSE} to {@link WindowClosingMode#DO_NOTHING_ON_CLOSE} + * via {@link #setDefaultCloseOperation(com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode)}. + * @see Window#destroy() + * @see #setDefaultCloseOperation(com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode) + */ + public void destroy() { + destroyImpl(true); + } + private void destroyImpl(final boolean disposeNewtChild) { + if(DEBUG) { + System.err.println("NewtCanvasJFX.dispose: (has parent "+(null!=parentWindow)+", hasNative "+(null!=nativeWindow)+",\n\t"+newtChild); + } + if( null != newtChild ) { + if(DEBUG) { + System.err.println("NewtCanvasJFX.dispose.1: EDTUtil cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + if( null != nativeWindow ) { + configureNewtChild(false); + newtChild.setVisible(false); + newtChild.reparentWindow(null, -1, -1, 0 /* hint */); + } + if( disposeNewtChild ) { + newtChild.destroy(); + newtChild = null; + } + } + if( null != parentWindow ) { + parentWindow.getScene().windowProperty().removeListener(sceneWindowChangeListener); + parentWindow.removeEventHandler(javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST, windowClosingListener); + parentWindow.removeEventHandler(javafx.stage.WindowEvent.WINDOW_SHOWN, windowShownListener); + parentWindow = null; + } + if( null != screen ) { + screen.getDevice().close(); + screen = null; + } + nativeWindow = null; + } + + private final boolean validateNative(final boolean completeReparent) { + if( null == parentWindow ) { + return false; + } + assert null == nativeWindow; + updatePosSizeCheck(); + if(0 >= clientArea.getWidth() || 0 >= clientArea.getHeight()) { + return false; + } + final long nativeWindowHandle = JFXAccessor.getWindowHandle(parentWindow); + if( 0 == nativeWindowHandle ) { + return false; + } + screen.getDevice().open(); + + /* Native handle for the control, used to associate with GLContext */ + final int visualID = JFXAccessor.getNativeVisualID(screen.getDevice(), nativeWindowHandle); + final boolean visualIDValid = NativeWindowFactory.isNativeVisualIDValidForProcessing(visualID); + if(DEBUG) { + System.err.println("NewtCanvasJFX.validateNative() windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", valid "+visualIDValid); + } + if( visualIDValid ) { + /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite). + * Note: JFX is owner of the native handle, hence no closing operation will be a NOP. */ + final CapabilitiesImmutable caps = new Capabilities(); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(screen.getDevice(), caps); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration( caps, caps, null, screen, visualID ); + if(DEBUG) { + System.err.println("NewtCanvasJFX.validateNative() factory: "+factory+", windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", chosen config: "+config); + // Thread.dumpStack(); + } + if (null == config) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + nativeWindow = new JFXNativeWindow(config, nativeWindowHandle); + if( completeReparent ) { + reparentWindow( true ); + } + } + + return null != nativeWindow; + } + + /** + * Sets a new NEWT child, provoking reparenting. + * <p> + * A previously detached <code>newChild</code> will be released to top-level status + * and made invisible. + * </p> + * <p> + * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code> + * produced much cleaner visual results. + * </p> + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an JFX conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * @return the previous attached newt child. + */ + public Window setNEWTChild(final Window newChild) { + final Window prevChild = newtChild; + if(DEBUG) { + System.err.println("NewtCanvasJFX.setNEWTChild.0: win "+newtWinHandleToHexString(prevChild)+" -> "+newtWinHandleToHexString(newChild)); + } + // remove old one + if(null != newtChild) { + reparentWindow( false ); + newtChild = null; + } + // add new one, reparent only if ready + newtChild = newChild; + if( null != newtChild && ( null != nativeWindow || validateNative(false /* completeReparent */) ) ) { + reparentWindow( true ); + } + return prevChild; + } + + private void reparentWindow(final boolean add) { + if( null == newtChild ) { + return; // nop + } + if(DEBUG) { + System.err.println("NewtCanvasJFX.reparentWindow.0: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + + newtChild.setFocusAction(null); // no AWT focus traversal .. + if(add) { + assert null != nativeWindow && null != parentWindow; + updatePosSizeCheck(); + final int x = clientArea.getX(); + final int y = clientArea.getY(); + final int w = clientArea.getWidth(); + final int h = clientArea.getHeight(); + + if(USE_JFX_EDT) { + // setup JFX EDT and start it + final Display newtDisplay = newtChild.getScreen().getDisplay(); + final EDTUtil oldEDTUtil = newtDisplay.getEDTUtil(); + if( ! ( oldEDTUtil instanceof JFXEDTUtil ) ) { + final EDTUtil newEDTUtil = new JFXEDTUtil(newtDisplay); + if(DEBUG) { + System.err.println("NewtCanvasJFX.reparentWindow.1: replacing EDTUtil "+oldEDTUtil+" -> "+newEDTUtil); + } + newEDTUtil.start(); + newtDisplay.setEDTUtil( newEDTUtil ); + } + } + + newtChild.setSize(w, h); + newtChild.reparentWindow(nativeWindow, x, y, Window.REPARENT_HINT_BECOMES_VISIBLE); + newtChild.setPosition(x, y); + newtChild.setVisible(true); + configureNewtChild(true); + newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener + + // force this JFX Canvas to be focus-able, + // since it is completely covered by the newtChild (z-order). + // FIXME ??? super.requestFocus(); + } else { + configureNewtChild(false); + newtChild.setVisible(false); + newtChild.reparentWindow(null, -1, -1, 0 /* hints */); + } + if(DEBUG) { + System.err.println("NewtCanvasJFX.reparentWindow.X: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + } + + private void configureNewtChild(final boolean attach) { + newtChildReady = attach; + if( null != newtChild ) { + newtChild.setKeyboardFocusHandler(null); + if(attach) { + newtChildClosingMode = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE); + } else { + newtChild.setFocusAction(null); + newtChild.setDefaultCloseOperation(newtChildClosingMode); + } + } + } + + /** @return the current NEWT child */ + public Window getNEWTChild() { + return newtChild; + } + + /** + * {@inheritDoc} + * @return this JFX Canvas {@link NativeWindow} representation, may be null in case it has not been realized + */ + @Override + public NativeWindow getNativeWindow() { return nativeWindow; } + + /** + * {@inheritDoc} + * @return this JFX Canvas {@link NativeSurface} representation, may be null in case it has not been realized + */ + @Override + public NativeSurface getNativeSurface() { return nativeWindow; } + + @Override + public WindowClosingMode getDefaultCloseOperation() { + return closingMode; + } + + @Override + public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) { + final WindowClosingMode old = closingMode; + closingMode = op; + return old; + } + + + boolean isParent() { + return null!=newtChild ; + } + + boolean isFullscreen() { + return null != newtChild && newtChild.isFullscreen(); + } + + private final void requestFocusNEWTChild() { + if( newtChildReady ) { + newtChild.setFocusAction(null); + newtChild.requestFocus(); + } + } + + @Override + public void requestFocus() { + NewtCanvasJFX.super.requestFocus(); + requestFocusNEWTChild(); + } + + private class JFXNativeWindow implements NativeWindow { + private final AbstractGraphicsConfiguration config; + private final long nativeWindowHandle; + private final InsetsImmutable insets; // only required to allow proper client position calculation on OSX + + public JFXNativeWindow(final AbstractGraphicsConfiguration config, final long nativeWindowHandle) { + this.config = config; + this.nativeWindowHandle = nativeWindowHandle; + this.insets = new Insets(0, 0, 0, 0); + } + + @Override + public int lockSurface() throws NativeWindowException, RuntimeException { + return NativeSurface.LOCK_SUCCESS; + } + + @Override + public void unlockSurface() { } + + @Override + public boolean isSurfaceLockedByOtherThread() { + return false; + } + + @Override + public Thread getSurfaceLockOwner() { + return null; + } + + @Override + public boolean surfaceSwap() { + return false; + } + + @Override + public void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { } + + @Override + public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + } + + @Override + public void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { } + + @Override + public long getSurfaceHandle() { + return 0; + } + + @Override + public int getWidth() { + return getSurfaceWidth(); // FIXME: Use 'scale' or an actual window-width + } + + @Override + public int getHeight() { + return getSurfaceHeight(); // FIXME: Use 'scale' or an actual window-width + } + + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + return pixelUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + } + + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + return windowUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + } + + @Override + public int getSurfaceWidth() { + return clientArea.getWidth(); + } + + @Override + public int getSurfaceHeight() { + return clientArea.getHeight(); + } + + @Override + public final NativeSurface getNativeSurface() { return this; } + + @Override + public AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config; + } + + @Override + public long getDisplayHandle() { + return config.getScreen().getDevice().getHandle(); + } + + @Override + public int getScreenIndex() { + return config.getScreen().getIndex(); + } + + @Override + public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { } + + @Override + public void destroy() { } + + @Override + public NativeWindow getParent() { + return null; + } + + @Override + public long getWindowHandle() { + return nativeWindowHandle; + } + + @Override + public InsetsImmutable getInsets() { + return insets; + } + + @Override + public int getX() { + return NewtCanvasJFX.this.clientArea.getX(); + } + + @Override + public int getY() { + return NewtCanvasJFX.this.clientArea.getY(); + } + + @Override + public Point getLocationOnScreen(final Point point) { + final Point los = NativeWindowFactory.getLocationOnScreen(this); // client window location on screen + if(null!=point) { + return point.translate(los); + } else { + return los; + } + } + + @Override + public boolean hasFocus() { + return isFocused(); + } + }; + + static String newtWinHandleToHexString(final Window w) { + return null != w ? toHexString(w.getWindowHandle()) : "nil"; + } + static String toHexString(final long l) { + return "0x"+Long.toHexString(l); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index f15c87beb..569780311 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -246,6 +246,16 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind } @Override + public final int getSupportedStateMask() { + return window.getSupportedStateMask(); + } + + @Override + public final String getSupportedStateMaskString() { + return window.getSupportedStateMaskString(); + } + + @Override public CapabilitiesChooser setCapabilitiesChooser(final CapabilitiesChooser chooser) { return window.setCapabilitiesChooser(chooser); } diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTDemoListener.java b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java index b70beae69..568b5d0bb 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/NEWTDemoListener.java +++ b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java @@ -25,28 +25,62 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package com.jogamp.opengl.test.junit.util; +package com.jogamp.newt.opengl.util; import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; import com.jogamp.common.util.IOUtil; import com.jogamp.nativewindow.CapabilitiesImmutable; import com.jogamp.nativewindow.ScalableSurface; +import com.jogamp.newt.Window; import com.jogamp.newt.Display; import com.jogamp.newt.Display.PointerIcon; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; -import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.FPSCounter; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLDrawable; +import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.util.Gamma; import com.jogamp.opengl.util.PNGPixelRect; import jogamp.newt.driver.PNGIcon; -public class NEWTDemoListener extends MouseAdapter implements KeyListener { +/** + * NEWT {@link GLWindow} Demo functionality + * <ul> + * <li>SPACE: Toggle animator {@link GLAnimatorControl#pause() pause}/{@link GLAnimatorControl#resume() resume}</li> + * <li>A: Toggle window {@link Window#setAlwaysOnTop(boolean) always on top}</li> + * <li>B: Toggle window {@link Window#setAlwaysOnBottom(boolean) always on bottom}</li> + * <li>C: Toggle different {@link Window#setPointerIcon(PointerIcon) pointer icons}</li> + * <li>D: Toggle window {@link Window#setUndecorated(boolean) decoration on/off}</li> + * <li>F: Toggle window {@link Window#setFullscreen(boolean) fullscreen on/off}</li> + * <li>Three-Finger Double-Tap: Toggle window {@link Window#setFullscreen(boolean) fullscreen on/off}</li> + * <li>G: Increase {@link Gamma#setDisplayGamma(GLDrawable, float, float, float) gamma} by 0.1, +SHIFT decrease gamma by 0.1</li> + * <li>I: Toggle {@link Window#setPointerVisible(boolean) pointer visbility}</li> + * <li>J: Toggle {@link Window#confinePointer(boolean) pointer jail (confine to window)}</li> + * <li>M: Toggle {@link Window#setMaximized(boolean, boolean) window maximized}: Y, +CTRL off, +SHIFT toggle X+Y, +ALT X</li> + * <li>P: Set window {@link Window#setPosition(int, int) position to 100/100}</li> + * <li>Q: Quit</li> + * <li>R: Toggle window {@link Window#setResizable(boolean) resizable}</li> + * <li>S: Toggle window {@link Window#setSticky(boolean) sticky}</li> + * <li>V: Toggle window {@link Window#setVisible(boolean) visibility} for 5s</li> + * <li>V: +CTRL: Rotate {@link GL#setSwapInterval(int) swap interval} -1, 0, 1</li> + * <li>W: {@link Window#warpPointer(int, int) Warp pointer} to center of window</li> + * <li>X: Toggle {@link ScalableSurface#setSurfaceScale(float[]) [{@link ScalableSurface#IDENTITY_PIXELSCALE}, {@link ScalableSurface#AUTOMAX_PIXELSCALE}]</li> + * </ul> + */ +public class NEWTDemoListener extends WindowAdapter implements KeyListener, MouseListener { protected final GLWindow glWindow; - protected final QuitAdapter quitAdapter; final PointerIcon[] pointerIcons; int pointerIconIdx = 0; float gamma = 1f; @@ -54,20 +88,16 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { float contrast = 1f; boolean confinedFixedCenter = false; - public NEWTDemoListener(final GLWindow glWin, final QuitAdapter quitAdapter, final PointerIcon[] pointerIcons) { + public NEWTDemoListener(final GLWindow glWin, final PointerIcon[] pointerIcons) { this.glWindow = glWin; - this.quitAdapter = quitAdapter; if( null != pointerIcons ) { this.pointerIcons = pointerIcons; } else { - this.pointerIcons = createPointerIcons(glWindow); + this.pointerIcons = createPointerIcons(glWindow.getScreen().getDisplay()); } } - public NEWTDemoListener(final GLWindow glWin, final PointerIcon[] pointerIcons) { - this(glWin, null, pointerIcons); - } public NEWTDemoListener(final GLWindow glWin) { - this(glWin, null, null); + this(glWin, null); } protected void printlnState(final String prelude) { @@ -76,17 +106,6 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { protected void printlnState(final String prelude, final String post) { System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString()+", "+post); } - protected void quitAdapterOff() { - if( null != quitAdapter ) { - quitAdapter.enable(false); - } - } - protected void quitAdapterOn() { - if( null != quitAdapter ) { - quitAdapter.clear(); - quitAdapter.enable(true); - } - } @Override public void keyPressed(final KeyEvent e) { @@ -97,44 +116,38 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { switch(keySymbol) { case KeyEvent.VK_SPACE: e.setConsumed(true); - new Thread() { + glWindow.invokeOnCurrentThread(new Runnable() { public void run() { if(glWindow.getAnimator().isPaused()) { glWindow.getAnimator().resume(); } else { glWindow.getAnimator().pause(); } - } - }.run(); + } } ); break; case KeyEvent.VK_A: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set alwaysontop pre]"); glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop()); printlnState("[set alwaysontop post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_B: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set alwaysonbottom pre]"); glWindow.setAlwaysOnBottom(!glWindow.isAlwaysOnBottom()); printlnState("[set alwaysonbottom post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_C: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { if( null != pointerIcons ) { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set pointer-icon pre]"); final PointerIcon currentPI = glWindow.getPointerIcon(); final PointerIcon newPI; @@ -146,28 +159,23 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { } glWindow.setPointerIcon( newPI ); printlnState("[set pointer-icon post]", currentPI+" -> "+glWindow.getPointerIcon()); - glWindow.setExclusiveContextThread(t); } - } }.start(); + } } ); break; case KeyEvent.VK_D: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); - // while( null != glWindow.getExclusiveContextThread() ) ; printlnState("[set undecorated pre]"); glWindow.setUndecorated(!glWindow.isUndecorated()); printlnState("[set undecorated post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_F: e.setConsumed(true); quitAdapterOff(); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set fullscreen pre]"); if( glWindow.isFullscreen() ) { glWindow.setFullscreen( false ); @@ -179,37 +187,33 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { } } printlnState("[set fullscreen post]"); - glWindow.setExclusiveContextThread(t); quitAdapterOn(); - } }.start(); + } } ); break; case KeyEvent.VK_G: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { final float newGamma = gamma + ( e.isShiftDown() ? -0.1f : 0.1f ); System.err.println("[set gamma]: "+gamma+" -> "+newGamma); if( Gamma.setDisplayGamma(glWindow, newGamma, brightness, contrast) ) { gamma = newGamma; } - } }.start(); + } } ); break; case KeyEvent.VK_I: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set pointer-visible pre]"); glWindow.setPointerVisible(!glWindow.isPointerVisible()); printlnState("[set pointer-visible post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_J: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set pointer-confined pre]", "warp-center: "+e.isShiftDown()); final boolean confine = !glWindow.isPointerConfined(); glWindow.confinePointer(confine); @@ -219,12 +223,11 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { } else if( !confine ) { setConfinedFixedCenter(false); } - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_M: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { // none: max-v // alt: max-h @@ -235,9 +238,9 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { horz = false; vert = false; } else if( e.isShiftDown() ) { - final boolean anyMax = glWindow.isMaximizedHorz() || glWindow.isMaximizedVert(); - horz = !anyMax; - vert = !anyMax; + final boolean bothMax = glWindow.isMaximizedHorz() && glWindow.isMaximizedVert(); + horz = !bothMax; + vert = !bothMax; } else if( !e.isAltDown() ) { horz = glWindow.isMaximizedHorz(); vert = !glWindow.isMaximizedVert(); @@ -248,82 +251,102 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { vert = glWindow.isMaximizedVert(); horz = glWindow.isMaximizedHorz(); } - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set maximize pre]", "max[vert "+vert+", horz "+horz+"]"); glWindow.setMaximized(horz, vert); printlnState("[set maximize post]", "max[vert "+vert+", horz "+horz+"]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_P: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set position pre]"); glWindow.setPosition(100, 100); printlnState("[set position post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); + break; + case KeyEvent.VK_Q: + if( quitAdapterEnabled && 0 == e.getModifiers() ) { + System.err.println("QUIT Key "+Thread.currentThread()); + quitAdapterShouldQuit = true; + } break; case KeyEvent.VK_R: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set resizable pre]"); glWindow.setResizable(!glWindow.isResizable()); printlnState("[set resizable post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_S: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set sticky pre]"); glWindow.setSticky(!glWindow.isSticky()); printlnState("[set sticky post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_V: e.setConsumed(true); - new Thread() { - public void run() { - final boolean wasVisible = glWindow.isVisible(); - { - final Thread t = glWindow.setExclusiveContextThread(null); - printlnState("[set visible pre]"); - glWindow.setVisible(!wasVisible); - printlnState("[set visible post]"); - glWindow.setExclusiveContextThread(t); - } - if( wasVisible && !e.isControlDown() ) { - try { - Thread.sleep(5000); - } catch (final InterruptedException e) { - e.printStackTrace(); + if( e.isControlDown() ) { + glWindow.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = -1; break; + case -1: i = 1; break; + case 1: i = 0; break; + default: i = 1; break; } - final Thread t = glWindow.setExclusiveContextThread(null); - printlnState("[reset visible pre]"); - glWindow.setVisible(true); - printlnState("[reset visible post]"); - glWindow.setExclusiveContextThread(t); + gl.setSwapInterval(i); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + if(drawable instanceof FPSCounter) { + ((FPSCounter)drawable).resetFPSCounter(); + } + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); + return true; } - } }.start(); + }); + } else { + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + final boolean wasVisible = glWindow.isVisible(); + { + printlnState("[set visible pre]"); + glWindow.setVisible(!wasVisible); + printlnState("[set visible post]"); + } + if( wasVisible && !e.isShiftDown() ) { + try { + java.lang.Thread.sleep(5000); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + printlnState("[reset visible pre]"); + glWindow.setVisible(true); + printlnState("[reset visible post]"); + } + } } ); + } break; case KeyEvent.VK_W: e.setConsumed(true); - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); printlnState("[set pointer-pos pre]"); glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2); printlnState("[set pointer-pos post]"); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); break; case KeyEvent.VK_X: e.setConsumed(true); @@ -365,7 +388,7 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { } @Override public void mouseClicked(final MouseEvent e) { - if(e.getClickCount() == 2 && e.getPointerCount() == 1) { + if(e.getClickCount() == 2 && e.getPointerCount() == 3) { glWindow.setFullscreen(!glWindow.isFullscreen()); System.err.println("setFullscreen: "+glWindow.isFullscreen()); } @@ -377,6 +400,43 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { glWindow.warpPointer(x, y); } } + @Override + public void mouseEntered(final MouseEvent e) {} + @Override + public void mouseExited(final MouseEvent e) {} + @Override + public void mousePressed(final MouseEvent e) {} + @Override + public void mouseReleased(final MouseEvent e) {} + @Override + public void mouseWheelMoved(final MouseEvent e) {} + + ///////////////////////////////////////////////////////////// + + private boolean quitAdapterShouldQuit = false; + private boolean quitAdapterEnabled = false; + private boolean quitAdapterEnabled2 = true; + + protected void quitAdapterOff() { + quitAdapterEnabled2 = false; + } + protected void quitAdapterOn() { + clearQuitAdapter(); + quitAdapterEnabled2 = true; + } + public void quitAdapterEnable(final boolean v) { quitAdapterEnabled = v; } + public void clearQuitAdapter() { quitAdapterShouldQuit = false; } + public boolean shouldQuit() { return quitAdapterShouldQuit; } + public void doQuit() { quitAdapterShouldQuit=true; } + + public void windowDestroyNotify(final WindowEvent e) { + if( quitAdapterEnabled && quitAdapterEnabled2 ) { + System.err.println("QUIT Window "+Thread.currentThread()); + quitAdapterShouldQuit = true; + } + } + + ///////////////////////////////////////////////////////////// public void setTitle() { setTitle(glWindow); @@ -389,80 +449,82 @@ public class NEWTDemoListener extends MouseAdapter implements KeyListener { final float[] sDPI = win.getPixelsPerMM(new float[2]); sDPI[0] *= 25.4f; sDPI[1] *= 25.4f; - win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]); + final float[] minSurfacePixelScale = win.getMinimumSurfaceScale(new float[2]); + final float[] maxSurfacePixelScale = win.getMaximumSurfaceScale(new float[2]); + final float[] reqSurfacePixelScale = win.getRequestedSurfaceScale(new float[2]); + final float[] hasSurfacePixelScale = win.getCurrentSurfaceScale(new float[2]); + win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]+ + ", scale[min "+minSurfacePixelScale[0]+"x"+minSurfacePixelScale[1]+", max "+ + maxSurfacePixelScale[0]+"x"+maxSurfacePixelScale[1]+", req "+ + reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" -> has "+ + hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+"]"); } - public static PointerIcon[] createPointerIcons(final GLWindow glWindow) { - final PointerIcon[] pointerIcons = { null, null, null, null, null }; + public static PointerIcon[] createPointerIcons(final Display disp) { + final List<PointerIcon> pointerIcons = new ArrayList<PointerIcon>(); { - final Display disp = glWindow.getScreen().getDisplay(); disp.createNative(); - int idx = 0; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/cross-grey-alpha-16x16.png" }, disp.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 8, 8); - System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); } catch (final Exception e) { - e.printStackTrace(); + System.err.println(e.getMessage()); } - pointerIcons[idx] = _pointerIcon; } - idx++; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/pointer-grey-alpha-16x24.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/pointer-grey-alpha-16x24.png" }, disp.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); - System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); } catch (final Exception e) { - e.printStackTrace(); + System.err.println(e.getMessage()); } - pointerIcons[idx] = _pointerIcon; } - idx++; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-red-alpha-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-red-alpha-64x64.png" }, disp.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); - System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); } catch (final Exception e) { - e.printStackTrace(); + System.err.println(e.getMessage()); } - pointerIcons[idx] = _pointerIcon; } - idx++; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-blue-alpha-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-blue-alpha-64x64.png" }, disp.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); - System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); } catch (final Exception e) { - e.printStackTrace(); + System.err.println(e.getMessage()); } - pointerIcons[idx] = _pointerIcon; } - idx++; if( PNGIcon.isAvailable() ) { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "jogamp-pointer-64x64.png" }, disp.getClass().getClassLoader(), null); try { final URLConnection urlConn = res.resolve(0); - final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); - System.err.printf("Create PointerIcon #%02d: %s%n", idx, image.toString()); - _pointerIcon = disp.createPointerIcon(image, 32, 0); - System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); + if( null != urlConn ) { + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size()+1, image.toString()); + _pointerIcon = disp.createPointerIcon(image, 32, 0); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); + } } catch (final Exception e) { - e.printStackTrace(); + System.err.println(e.getMessage()); } - pointerIcons[idx] = _pointerIcon; } - idx++; } - return pointerIcons; + return pointerIcons.toArray(new PointerIcon[pointerIcons.size()]); } - }
\ No newline at end of file diff --git a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java index 186ffb162..d1bd638d8 100644 --- a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java +++ b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java @@ -38,8 +38,10 @@ import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.NativeWindow; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.NativeWindowHolder; import com.jogamp.nativewindow.SurfaceUpdatedListener; import com.jogamp.nativewindow.WindowClosingProtocol; +import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode; import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.nativewindow.util.Point; @@ -70,12 +72,13 @@ import com.jogamp.newt.util.EDTUtil; * Implementation allows use of custom {@link GLCapabilities}. * </p> */ -public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { +public class NewtCanvasSWT extends Canvas implements NativeWindowHolder, WindowClosingProtocol { private static final boolean DEBUG = Debug.debug("Window"); private final AbstractGraphicsScreen screen; - private WindowClosingMode newtChildCloseOp = WindowClosingMode.DISPOSE_ON_CLOSE; + private WindowClosingMode newtChildClosingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private final WindowClosingMode closingMode = WindowClosingMode.DISPOSE_ON_CLOSE; private volatile Rectangle clientArea; private volatile SWTNativeWindow nativeWindow; @@ -330,17 +333,28 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { return new Point(parentLoc[0].x, parentLoc[0].y); } - /** @return this SWT Canvas NativeWindow representation, may be null in case it has not been realized. */ + /** + * {@inheritDoc} + * @return this SWT Canvas {@link NativeWindow} representation, may be null in case it has not been realized + */ + @Override public NativeWindow getNativeWindow() { return nativeWindow; } + /** + * {@inheritDoc} + * @return this SWT Canvas {@link NativeSurface} representation, may be null in case it has not been realized + */ + @Override + public NativeSurface getNativeSurface() { return nativeWindow; } + @Override public WindowClosingMode getDefaultCloseOperation() { - return newtChildCloseOp; // TODO: implement ?! + return closingMode; } @Override public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) { - return newtChildCloseOp = op; // TODO: implement ?! + return closingMode; // TODO: implement! } @@ -401,10 +415,10 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { if( null != newtChild ) { newtChild.setKeyboardFocusHandler(null); if(attach) { - newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE); + newtChildClosingMode = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE); } else { newtChild.setFocusAction(null); - newtChild.setDefaultCloseOperation(newtChildCloseOp); + newtChild.setDefaultCloseOperation(newtChildClosingMode); } } } diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java index 8bf4bc20f..05df63794 100644 --- a/src/newt/classes/com/jogamp/newt/util/MainThread.java +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -45,6 +45,7 @@ import java.util.List; import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; @@ -171,15 +172,14 @@ public class MainThread { return res; } - static class UserApp extends Thread { + static class UserApp extends InterruptSource.Thread { private final String mainClassNameShort; private final String mainClassName; private final String[] mainClassArgs; private final Method mainClassMain; - private List<Thread> nonDaemonThreadsAtStart; + private List<java.lang.Thread> nonDaemonThreadsAtStart; public UserApp(final String mainClassName, final String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException { - super(); this.mainClassName=mainClassName; this.mainClassArgs=mainClassArgs; @@ -200,10 +200,10 @@ public class MainThread { @Override public void run() { nonDaemonThreadsAtStart = getNonDaemonThreads(); - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart); // start user app .. try { - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" invoke "+mainClassName); mainClassMain.invoke(null, new Object[] { mainClassArgs } ); } catch (final InvocationTargetException ite) { ite.getTargetException().printStackTrace(); @@ -219,30 +219,30 @@ public class MainThread { while( 0 < ( ndtr = getNonDaemonThreadCount(nonDaemonThreadsAtStart) ) ) { if(DEBUG) System.err.println("MainAction.run(): post user app, non daemon threads alive: "+ndtr); try { - Thread.sleep(1000); + java.lang.Thread.sleep(1000); } catch (final InterruptedException e) { e.printStackTrace(); } } - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin: "+ndtr); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" user app fin: "+ndtr); } if ( useMainThread ) { if(isMacOSX) { try { if(DEBUG) { - System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0"); + System.err.println("MainAction.main(): "+java.lang.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"); + System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.X"); } } catch (final Exception e) { e.printStackTrace(); } } else { - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)"); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" MainAction fin - System.exit(0)"); System.exit(0); } } diff --git a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java index cc159e6ed..c30576ff4 100644 --- a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java @@ -42,10 +42,8 @@ import com.jogamp.opengl.GLPipelineFactory; import jogamp.newt.Debug; -import com.jogamp.common.util.IOUtil; -import com.jogamp.newt.Display; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.Window; -import com.jogamp.newt.Display.PointerIcon; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.MouseListener; @@ -53,13 +51,18 @@ import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; -/** Shows how to deploy an applet using JOGL. This demo must be - referenced from a web page via an <applet> tag. */ - +/** + * Shows how to deploy an applet using JOGL. + * This demo must be referenced from a web page via an <applet> tag. + * <p> + * The demo code uses {@link NEWTDemoListener} functionality. + * </p> + */ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { public static final boolean DEBUG = Debug.debug("Applet"); @@ -69,7 +72,6 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { boolean glClosable; boolean glDebug; boolean glTrace; - PointerIcon pointerIconTest = null; GLEventListener glEventListener = null; GLWindow glWindow = null; @@ -193,8 +195,13 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.addKeyListener((KeyListener)glEventListener); } + glWindow.addWindowListener(reparentHomeListener); + if(!noDefaultKeyListener) { glWindow.addKeyListener(this); + final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow); + glWindow.addKeyListener(newtDemoListener); + glWindow.addMouseListener(newtDemoListener); } glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err); @@ -220,7 +227,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { null == glWindow.getParent() && null != parentWin && 0 != parentWin.getWindowHandle() ) { // we may be called directly by the native EDT - new Thread(new Runnable() { + new InterruptSource.Thread(null, new Runnable() { @Override public void run() { if( glWindow.isNativeValid() && null != parentWin && 0 != parentWin.getWindowHandle() ) { @@ -235,24 +242,13 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { if(isValid) { glWindow.setVisible(true); glWindow.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); - if( null == pointerIconTest ) { - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } ); - final Display disp = glWindow.getScreen().getDisplay(); - try { - pointerIconTest = disp.createPointerIcon(res, 8, 8); - } catch (final Exception e) { - e.printStackTrace(); - } - } glAnimator.start(); parentWin = glWindow.getParent(); - glWindow.addWindowListener(reparentHomeListener); } } public void stop() { if(null!=glAnimator) { - glWindow.removeWindowListener(reparentHomeListener); glAnimator.stop(); glWindow.setVisible(false); } @@ -291,10 +287,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, _gl, new Object[] { System.err } ) ); } catch (final Exception e) {e.printStackTrace();} } - - if(glSwapInterval>=0) { - _gl.setSwapInterval(glSwapInterval); - } + _gl.setSwapInterval(glSwapInterval); } @Override public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { @@ -315,27 +308,14 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { if( !e.isPrintableKey() || e.isAutoRepeat() ) { return; } - if(e.getKeyChar()=='d') { - new Thread() { - public void run() { - glWindow.setUndecorated(!glWindow.isUndecorated()); - } }.start(); - } if(e.getKeyChar()=='f') { - new Thread() { - public void run() { - glWindow.setFullscreen(!glWindow.isFullscreen()); - } }.start(); - } else if(e.getKeyChar()=='a') { - new Thread() { - public void run() { - glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop()); - } }.start(); - } else if(e.getKeyChar()=='r' && null!=parentWin) { - new Thread() { + + if(e.getKeyChar()=='r' && 0==e.getModifiers() && null!=parentWin) { + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { if(null == glWindow.getParent()) { - glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */); - } else { + glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */); + } else { final InsetsImmutable insets = glWindow.getInsets(); final int x, y; if ( 0 >= insets.getTopHeight() ) { @@ -349,43 +329,13 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.reparentWindow(null, x, y, 0 /* hints */); glWindow.setDefaultCloseOperation( glClosable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE ); } - } }.start(); - } else if(e.getKeyChar()=='c') { - new Thread() { - public void run() { - System.err.println("[set pointer-icon pre]"); - final PointerIcon currentPI = glWindow.getPointerIcon(); - glWindow.setPointerIcon( currentPI == pointerIconTest ? null : pointerIconTest); - System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon()); - } }.start(); - } else if(e.getKeyChar()=='i') { - new Thread() { - public void run() { - System.err.println("[set mouse visible pre]: "+glWindow.isPointerVisible()); - glWindow.setPointerVisible(!glWindow.isPointerVisible()); - System.err.println("[set mouse visible post]: "+glWindow.isPointerVisible()); - } }.start(); - } else if(e.getKeyChar()=='j') { - new Thread() { - public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); - System.err.println("[set mouse confined pre]: "+glWindow.isPointerConfined()); - glWindow.confinePointer(!glWindow.isPointerConfined()); - System.err.println("[set mouse confined post]: "+glWindow.isPointerConfined()); - glWindow.setExclusiveContextThread(t); - } }.start(); - } else if(e.getKeyChar()=='w') { - new Thread() { - public void run() { - System.err.println("[set mouse pos pre]"); - glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2); - System.err.println("[set mouse pos post]"); - } }.start(); + } } ); } } @Override public void keyReleased(final KeyEvent e) { } + } diff --git a/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java b/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java index 9b9b7d532..fce43d71f 100644 --- a/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java +++ b/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java @@ -243,7 +243,7 @@ public class JOGLNewtApplet3Run implements Applet3 { } this.ctx = ctx; String glEventListenerClazzName=null; - int glSwapInterval=0; + int glSwapInterval=1; boolean glDebug=false; boolean glTrace=false; boolean glNoDefaultKeyListener = false; diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java index bf46ce609..ff713410b 100644 --- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java +++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java @@ -44,6 +44,8 @@ import com.jogamp.nativewindow.NativeWindowException; import jogamp.common.util.locks.LockDebugUtil; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.RunnableTask; import com.jogamp.common.util.locks.Lock; import com.jogamp.newt.util.EDTUtil; @@ -68,7 +70,7 @@ public class DefaultEDTUtil implements EDTUtil { this.threadGroup = tg; this.name=Thread.currentThread().getName()+"-"+name+"-EDT-"; this.dispatchMessages=dispatchMessages; - this.edt = new NEDT(threadGroup, name); + this.edt = new NEDT(threadGroup, this.name); this.edt.setDaemon(true); // don't stop JVM from shutdown .. } @@ -169,8 +171,7 @@ public class DefaultEDTUtil implements EDTUtil { }; private final boolean invokeImpl(boolean wait, Runnable task, final boolean stop, final boolean provokeError) { - Throwable throwable = null; - RunnableTask rTask = null; + final RunnableTask rTask; final Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution synchronized(edtLock) { // lock the EDT status @@ -187,6 +188,7 @@ public class DefaultEDTUtil implements EDTUtil { task.run(); } wait = false; // running in same thread (EDT) -> no wait + rTask = null; if( stop ) { edt.shouldStop = true; if( edt.tasks.size()>0 ) { @@ -230,18 +232,19 @@ public class DefaultEDTUtil implements EDTUtil { } } else { wait = false; + rTask = null; } } } if( wait ) { try { - rTaskLock.wait(); // free lock, allow execution of rTask + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); + throw new InterruptedRuntimeException(ie); } + final Throwable throwable = rTask.getThrowable(); if(null!=throwable) { if(throwable instanceof NativeWindowException) { throw (NativeWindowException)throwable; @@ -268,13 +271,13 @@ public class DefaultEDTUtil implements EDTUtil { return false; } synchronized(_edt.tasks) { - while(_edt.isRunning && _edt.tasks.size()>0) { - try { + try { + while(_edt.isRunning && _edt.tasks.size()>0) { _edt.tasks.notifyAll(); _edt.tasks.wait(); - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } return true; } @@ -284,12 +287,12 @@ public class DefaultEDTUtil implements EDTUtil { final public boolean waitUntilStopped() { synchronized(edtLock) { if(edt.isRunning && edt != Thread.currentThread() ) { - while( edt.isRunning ) { - try { + try { + while( edt.isRunning ) { edtLock.wait(); - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } return true; } else { @@ -298,13 +301,13 @@ public class DefaultEDTUtil implements EDTUtil { } } - class NEDT extends Thread { + class NEDT extends InterruptSource.Thread { volatile boolean shouldStop = false; volatile boolean isRunning = false; final ArrayList<RunnableTask> tasks = new ArrayList<RunnableTask>(); // one shot tasks public NEDT(final ThreadGroup tg, final String name) { - super(tg, name); + super(tg, null, name); } final public boolean isRunning() { @@ -347,11 +350,11 @@ public class DefaultEDTUtil implements EDTUtil { RunnableTask task = null; synchronized(tasks) { // wait for tasks - if(!shouldStop && tasks.size()==0) { + if( !shouldStop && tasks.size()==0 ) { try { tasks.wait(pollPeriod); } catch (final InterruptedException e) { - e.printStackTrace(); + throw new InterruptedRuntimeException(e); } } // execute one task, if available @@ -375,7 +378,7 @@ public class DefaultEDTUtil implements EDTUtil { } if(!task.hasWaiter() && null != task.getThrowable()) { // at least dump stack-trace in case nobody waits for result - System.err.println("DefaultEDT.run(): Caught exception occured on thread "+Thread.currentThread().getName()+": "+task.toString()); + System.err.println("DefaultEDT.run(): Caught exception occured on thread "+java.lang.Thread.currentThread().getName()+": "+task.toString()); task.getThrowable().printStackTrace(); } } diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index cc1f3d8e0..61a39c133 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -37,6 +37,7 @@ package jogamp.newt; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.newt.Display; import com.jogamp.newt.NewtFactory; @@ -117,6 +118,8 @@ public abstract class DisplayImpl extends Display { return null; } final PointerIconImpl[] res = { null }; + final Exception[] ex = { null }; + final String exStr = "Could not resolve "+pngResource.resourcePaths[0]; runOnEDTIfAvail(true, new Runnable() { public void run() { try { @@ -125,7 +128,7 @@ public abstract class DisplayImpl extends Display { } final URLConnection urlConn = pngResource.resolve(0); if( null == urlConn ) { - throw new IOException("Could not resolve "+pngResource.resourcePaths[0]); + throw new IOException(exStr); } final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), getNativePointerIconPixelFormat(), @@ -137,20 +140,32 @@ public abstract class DisplayImpl extends Display { if( DEBUG_POINTER_ICON ) { System.err.println("createPointerIconPNG.0: "+image+", handle: "+toHexString(handle)+", hot "+hotspot); } - if( 0 != handle ) { - res[0] = new PointerIconImpl(DisplayImpl.this, image, hotspot, handle); - if( DEBUG_POINTER_ICON ) { - System.err.println("createPointerIconPNG.0: "+res[0]); - } + if( 0 == handle ) { + throw new IOException(exStr); + } + res[0] = new PointerIconImpl(DisplayImpl.this, image, hotspot, handle); + if( DEBUG_POINTER_ICON ) { + System.err.println("createPointerIconPNG.0: "+res[0]); } } catch (final Exception e) { - e.printStackTrace(); + ex[0] = e; } } } ); - if( null != res[0] ) { - synchronized(pointerIconList) { - pointerIconList.add(res[0]); + if( null != ex[0] ) { + final Exception e = ex[0]; + if( e instanceof IllegalArgumentException) { + throw new IllegalArgumentException(e); } + if( e instanceof IllegalStateException) { + throw new IllegalStateException(e); + } + throw new IOException(e); + } + if( null == res[0] ) { + throw new IOException(exStr); + } + synchronized(pointerIconList) { + pointerIconList.add(res[0]); } return res[0]; } @@ -697,8 +712,9 @@ public abstract class DisplayImpl extends Display { } else { throw re; } + } finally { + eventTask.notifyCaller(); } - eventTask.notifyCaller(); } @Override @@ -725,7 +741,10 @@ public abstract class DisplayImpl extends Display { } if( null != _events ) { for (int i=0; i < _events.size(); i++) { - dispatchMessage(_events.get(i)); + final NEWTEventTask e = _events.get(i); + if( !e.isDispatched() ) { + dispatchMessage(e); + } } } } @@ -759,11 +778,12 @@ public abstract class DisplayImpl extends Display { haveEvents = true; eventsLock.notifyAll(); } - if( wait ) { + while( wait && !eTask.isDispatched() ) { try { lock.wait(); } catch (final InterruptedException ie) { - throw new RuntimeException(ie); + eTask.setDispatched(); // Cancels NEWTEvent .. + throw new InterruptedRuntimeException(ie); } if( null != eTask.getException() ) { throw eTask.getException(); diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java index 09e318957..f4b8ecd42 100644 --- a/src/newt/classes/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java @@ -42,7 +42,6 @@ import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.MutableSurface; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.Point; import com.jogamp.newt.MonitorDevice; @@ -116,6 +115,10 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface { return false; // nop } + @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask; + } @Override protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { @@ -147,10 +150,5 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface { protected Point getLocationOnScreenImpl(final int x, final int y) { return new Point(x,y); } - - @Override - protected void updateInsetsImpl(final Insets insets) { - // nop .. - } } diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 241192c6c..0d395b970 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -73,6 +73,7 @@ import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.newt.Display; import com.jogamp.newt.Display.PointerIcon; import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.MonitorMode; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Screen; import com.jogamp.newt.Window; @@ -95,11 +96,12 @@ import com.jogamp.newt.event.WindowUpdateEvent; public abstract class WindowImpl implements Window, NEWTEventConsumer { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE; + private static final boolean DEBUG_FREEZE_AT_VISIBILITY_FAILURE; static { Debug.initSingleton(); DEBUG_TEST_REPARENT_INCOMPATIBLE = PropertyAccess.isPropertyDefined("newt.test.Window.reparent.incompatible", true); - + DEBUG_FREEZE_AT_VISIBILITY_FAILURE = PropertyAccess.isPropertyDefined("newt.debug.Window.visibility.failure.freeze", true); ScreenImpl.initSingleton(); } @@ -147,7 +149,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private static final PointerType[] constMousePointerTypes = new PointerType[] { PointerType.Mouse }; // - // Volatile: Multithread Mutable Access + // Volatile: Multithreaded Mutable Access // private volatile long windowHandle = 0; // lifecycle critical private volatile int pixWidth = 128, pixHeight = 128; // client-area size w/o insets in pixel units, default: may be overwritten by user @@ -173,8 +175,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer protected CapabilitiesChooser capabilitiesChooser = null; // default null -> default private List<MonitorDevice> fullscreenMonitors = null; - private final RectangleImmutable undefSize = new Rectangle(0, 0, 0, 0); - private final Rectangle minmax_size = new Rectangle(undefSize); // current min/max size or undef private int nfs_width, nfs_height, nfs_x, nfs_y; // non fullscreen client-area size/pos w/o insets private NativeWindow nfs_parent = null; // non fullscreen parent, in case explicit reparenting is performed (offscreen) private String title = "Newt Window"; @@ -182,6 +182,25 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private LifecycleHook lifecycleHook = null; // + // Quirks + // + + /** + * Bug 1249 and Bug 1250: Visibility issues on X11 + * <ul> + * <li>setVisible(false) IconicState not listening to _NET_WM_STATE_HIDDEN</li> + * <li>setVisible(true) not restoring from _NET_WM_STATE_HIDDEN</li> + * </ul> + * <p> + * If {@code true} fall back to traditional visibility state, + * i.e. {@code fast=true}. + * </p> + */ + protected static final int QUIRK_BIT_VISIBILITY = 0; + /** Quirk mask */ + protected static final Bitfield quirks = Bitfield.Factory.synchronize(Bitfield.Factory.create(32)); + + // // State Mask // @@ -189,50 +208,60 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * Number of all public state bits, {@value}. * <p>Defaults to {@code false}.</p> * @see #getStateMask() + * @since 2.3.2 */ - protected static final int STATE_BIT_COUNT_ALL_PUBLIC = 15; + protected static final int STATE_BIT_COUNT_ALL_PUBLIC = STATE_BIT_POINTERCONFINED + 1; /** Bitmask for {@link #STATE_BIT_COUNT_ALL_PUBLIC} */ protected static final int STATE_MASK_ALL_PUBLIC = ( 1 << STATE_BIT_COUNT_ALL_PUBLIC ) - 1; // - // Additional private state-mask bits and mask values + // Additional private reconfigure state-mask bits and mask values // - /** - * <p>Bit number {@value}.</p> - * <p>Defaults to {@code false}.</p> - * @see #getStateMask() - */ - /* pp */ static final int STATE_BIT_FULLSCREEN_SPAN = 12; - /* pp */ static final int PSTATE_BIT_MINMAXSIZE_SET = 27; - /* pp */ static final int PSTATE_BIT_FOCUS_CHANGE_BROKEN = 28; - /* pp */ static final int PSTATE_BIT_FULLSCREEN_MAINMONITOR = 29; // true - /* pp */ static final int PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP = 30; // non fullscreen alwaysOnTop setting - /* pp */ static final int PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE = 31; // non fullscreen resizable setting + protected static final int STATE_BIT_FULLSCREEN_SPAN = STATE_BIT_COUNT_ALL_PUBLIC; + + protected static final int STATE_BIT_COUNT_ALL_RECONFIG = STATE_BIT_FULLSCREEN_SPAN + 1; + /** Bitmask for {@link #STATE_BIT_COUNT_ALL_RECONFIG} */ + protected static final int STATE_MASK_ALL_RECONFIG = ( 1 << STATE_BIT_COUNT_ALL_RECONFIG ) - 1; + + protected static final int STATE_MASK_ALL_PUBLIC_SUPPORTED = STATE_MASK_ALL_PUBLIC & ~STATE_MASK_AUTOPOSITION; + + // + // Additional private non-reconfigure state-mask bits and mask values + // + + /* pp */ static final int PSTATE_BIT_FOCUS_CHANGE_BROKEN = 30; + /* pp */ static final int PSTATE_BIT_FULLSCREEN_MAINMONITOR = 31; // true /** Bitmask for {@link #STATE_BIT_FULLSCREEN_SPAN}, {@value}. */ /* pp */ static final int STATE_MASK_FULLSCREEN_SPAN = 1 << STATE_BIT_FULLSCREEN_SPAN; + /* pp */ static final int PSTATE_MASK_FOCUS_CHANGE_BROKEN = 1 << PSTATE_BIT_FOCUS_CHANGE_BROKEN; /* pp */ static final int PSTATE_MASK_FULLSCREEN_MAINMONITOR = 1 << PSTATE_BIT_FULLSCREEN_MAINMONITOR; - /* pp */ static final int PSTATE_MASK_FULLSCREEN_NFS_ALWAYSONTOP = 1 << PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP; - /* pp */ static final int PSTATE_MASK_FULLSCREEN_NFS_RESIZABLE = 1 << PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE; + + /** + * Mask covering all preserved non-fullscreen (NFS) states + * while in fullscreen mode. + */ + private static final int STATE_MASK_FULLSCREEN_NFS = STATE_MASK_ALWAYSONTOP | + STATE_MASK_RESIZABLE | + STATE_MASK_MAXIMIZED_VERT | + STATE_MASK_MAXIMIZED_HORZ; /** * Reconfig mask for createNativeImpl(..) taking out from {@link #getStateMask()}: * <ul> - * <li>{@link #STATE_MASK_VISIBLE}</li> * <li>{@link #STATE_MASK_FULLSCREEN}</li> * <li>{@link #STATE_MASK_POINTERVISIBLE}</li> * <li>{@link #STATE_MASK_POINTERCONFINED}</li> * </ul> * Above taken out states are achieved from caller createNative() 'manually'. + * @since 2.3.2 */ - protected final int STATE_MASK_CREATENATIVE = STATE_MASK_UNDECORATED | - STATE_MASK_ALWAYSONTOP | - STATE_MASK_ALWAYSONBOTTOM | - STATE_MASK_STICKY | - STATE_MASK_RESIZABLE | - STATE_MASK_MAXIMIZED_VERT | - STATE_MASK_MAXIMIZED_HORZ; + protected static final int STATE_MASK_CREATENATIVE = STATE_MASK_ALL_PUBLIC & + ~( STATE_MASK_FULLSCREEN | + STATE_MASK_POINTERVISIBLE | + STATE_MASK_POINTERCONFINED + ); // // Additional private state-mask mask values for reconfiguration only // (keep in sync w/ src/newt/native/Window.h) @@ -249,15 +278,28 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer protected static final int CHANGE_MASK_MAXIMIZED_HORZ = 1 << 22; protected static final int CHANGE_MASK_FULLSCREEN = 1 << 21; + /** Regular state mask */ /* pp */ final Bitfield stateMask = Bitfield.Factory.synchronize(Bitfield.Factory.create(32)); + /** Non fullscreen state mask */ + private final Bitfield stateMaskNFS = Bitfield.Factory.synchronize(Bitfield.Factory.create(32)); + + /** Default is all but {@link #STATE_MASK_FULLSCREEN_SPAN}. */ + protected int supportedReconfigStateMask = 0; + /** See {@link #getSupportedStateMask()}, i.e. {@link #STATE_MASK_VISIBLE} | {@link #STATE_MASK_FOCUSED} | {@link STATE_MASK_FULLSCREEN}. */ + protected static final int minimumReconfigStateMask = STATE_MASK_VISIBLE | STATE_MASK_FOCUSED | STATE_MASK_FULLSCREEN; + /* pp */ final void resetStateMask() { stateMask.clearField(false); - stateMask.set(STATE_BIT_AUTOPOSITION); - stateMask.put(STATE_BIT_CHILDWIN, null != parentWindow); - stateMask.set(STATE_BIT_RESIZABLE); - stateMask.set(STATE_BIT_POINTERVISIBLE); - stateMask.set(PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE); - stateMask.set(PSTATE_BIT_FULLSCREEN_MAINMONITOR); + stateMask.put32(0, 32, + STATE_MASK_AUTOPOSITION | + ( null != parentWindow ? STATE_MASK_CHILDWIN : 0 ) | + STATE_MASK_RESIZABLE | + STATE_MASK_POINTERVISIBLE | + PSTATE_MASK_FULLSCREEN_MAINMONITOR); + stateMaskNFS.clearField(false); + normPosSizeStored[0] = false; + normPosSizeStored[1] = false; + supportedReconfigStateMask = STATE_MASK_ALL_RECONFIG; } @Override @@ -273,16 +315,29 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public final int getStateMask() { return stateMask.get32(0, STATE_BIT_COUNT_ALL_PUBLIC); } + @Override public final String getStateMaskString() { return appendStateBits(new StringBuilder(), stateMask.get32(0, STATE_BIT_COUNT_ALL_PUBLIC), false).toString(); } + @Override + public final int getSupportedStateMask() { + return supportedReconfigStateMask & STATE_MASK_ALL_PUBLIC_SUPPORTED; + } + + @Override + public final String getSupportedStateMaskString() { + return appendStateBits(new StringBuilder(), getSupportedStateMask(), true).toString(); + } + protected static StringBuilder appendStateBits(final StringBuilder sb, final int mask, final boolean showChangeFlags) { sb.append("["); - if( showChangeFlags && 0 != ( CHANGE_MASK_VISIBILITY & mask) ) { - sb.append("*"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_VISIBILITY & mask) ) { + sb.append("*"); + } if( 0 != ( CHANGE_MASK_VISIBILITY_FAST & mask) ) { sb.append("*"); } @@ -292,9 +347,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append((0 != ( STATE_MASK_AUTOPOSITION & mask))?"autopos, ":""); - if( showChangeFlags && 0 != ( CHANGE_MASK_PARENTING & mask) ) { - sb.append("*"); - sb.append((0 != ( STATE_MASK_CHILDWIN & mask))?"child":"top"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_PARENTING & mask) ) { + sb.append("*"); + } + sb.append((0 != ( STATE_MASK_CHILDWIN & mask))?"child":"toplevel"); sb.append(", "); } else if( 0 != ( STATE_MASK_CHILDWIN & mask) ) { sb.append("child"); @@ -303,8 +360,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append((0 != ( STATE_MASK_FOCUSED & mask))?"focused, ":""); - if( showChangeFlags && 0 != ( CHANGE_MASK_DECORATION & mask) ) { - sb.append("*"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_DECORATION & mask) ) { + sb.append("*"); + } sb.append((0 != ( STATE_MASK_UNDECORATED & mask))?"undecor":"decor"); sb.append(", "); } else if( 0 != ( STATE_MASK_UNDECORATED & mask) ) { @@ -312,8 +371,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append(", "); } - if( showChangeFlags && 0 != ( CHANGE_MASK_ALWAYSONTOP & mask) ) { - sb.append("*"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_ALWAYSONTOP & mask) ) { + sb.append("*"); + } sb.append((0 != ( STATE_MASK_ALWAYSONTOP & mask))?"aontop":"!aontop"); sb.append(", "); } else if( 0 != ( STATE_MASK_ALWAYSONTOP & mask) ) { @@ -321,8 +382,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append(", "); } - if( showChangeFlags && 0 != ( CHANGE_MASK_ALWAYSONBOTTOM & mask) ) { - sb.append("*"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_ALWAYSONBOTTOM & mask) ) { + sb.append("*"); + } sb.append((0 != ( STATE_MASK_ALWAYSONBOTTOM & mask))?"aonbottom":"!aonbottom"); sb.append(", "); } else if( 0 != ( STATE_MASK_ALWAYSONBOTTOM & mask) ) { @@ -330,8 +393,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append(", "); } - if( showChangeFlags && 0 != ( CHANGE_MASK_STICKY & mask) ) { - sb.append("*"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_STICKY & mask) ) { + sb.append("*"); + } sb.append((0 != ( STATE_MASK_STICKY & mask))?"sticky":"unsticky"); sb.append(", "); } else if( 0 != ( STATE_MASK_STICKY & mask) ) { @@ -339,8 +404,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append(", "); } - if( showChangeFlags && 0 != ( CHANGE_MASK_RESIZABLE & mask) ) { - sb.append("*"); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_RESIZABLE & mask) ) { + sb.append("*"); + } sb.append((0 != ( STATE_MASK_RESIZABLE & mask))?"resizable":"unresizable"); sb.append(", "); } else if( 0 == ( STATE_MASK_RESIZABLE & mask) ) { @@ -348,21 +415,23 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append(", "); } - if( showChangeFlags && 0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & mask) ) { + if( showChangeFlags ) { sb.append("max["); - if( 0 != ( STATE_MASK_MAXIMIZED_HORZ & mask) ) { - if( 0 != ( CHANGE_MASK_MAXIMIZED_HORZ & mask) ) { - sb.append("*"); - } - sb.append("h"); - sb.append(", "); + if( 0 != ( CHANGE_MASK_MAXIMIZED_HORZ & mask) ) { + sb.append("*"); } - if( 0 != ( STATE_MASK_MAXIMIZED_VERT & mask) ) { - if( 0 != ( CHANGE_MASK_MAXIMIZED_VERT & mask) ) { - sb.append("*"); - } - sb.append("v"); + if( 0 == ( STATE_MASK_MAXIMIZED_HORZ & mask) ) { + sb.append("!"); + } + sb.append("h"); + sb.append(", "); + if( 0 != ( CHANGE_MASK_MAXIMIZED_VERT & mask) ) { + sb.append("*"); + } + if( 0 == ( STATE_MASK_MAXIMIZED_VERT & mask) ) { + sb.append("!"); } + sb.append("v"); sb.append("], "); } else if( 0 != ( ( STATE_MASK_MAXIMIZED_HORZ | STATE_MASK_MAXIMIZED_VERT ) & mask) ) { sb.append("max["); @@ -375,28 +444,47 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sb.append("], "); } - if( showChangeFlags && 0 != ( CHANGE_MASK_FULLSCREEN & mask) ) { - sb.append("*"); - sb.append((0 != ( STATE_MASK_FULLSCREEN & mask))?"fullscreen":"window"); - sb.append((0 != ( STATE_MASK_FULLSCREEN_SPAN & mask))?"[span]":"[]"); - sb.append(", "); + if( showChangeFlags ) { + if( 0 != ( CHANGE_MASK_FULLSCREEN & mask) ) { + sb.append("*"); + } + sb.append("fullscreen["); + sb.append(0 != ( STATE_MASK_FULLSCREEN & mask)); + sb.append((0 != ( STATE_MASK_FULLSCREEN_SPAN & mask))?", span":""); + sb.append("], "); } else if( 0 != ( STATE_MASK_FULLSCREEN & mask) ) { sb.append("fullscreen"); sb.append(", "); } - if( 0 == ( STATE_MASK_POINTERVISIBLE & mask) || - 0 != ( STATE_MASK_POINTERCONFINED & mask) ) - { - sb.append("pointer["); - if( 0 == ( STATE_MASK_POINTERVISIBLE & mask) ) { - sb.append("invisible"); + if( showChangeFlags ) { + sb.append("pointer["); + if( 0 == ( STATE_MASK_POINTERVISIBLE & mask) ) { + sb.append("invisible"); + } else { + sb.append("visible"); + } sb.append(", "); + if( 0 != ( STATE_MASK_POINTERCONFINED & mask) ) { + sb.append("confined"); + } else { + sb.append("free"); + } + sb.append("]"); + } else { + if( 0 == ( STATE_MASK_POINTERVISIBLE & mask) || + 0 != ( STATE_MASK_POINTERCONFINED & mask) ) + { + sb.append("pointer["); + if( 0 == ( STATE_MASK_POINTERVISIBLE & mask) ) { + sb.append("invisible"); + sb.append(", "); + } + if( 0 != ( STATE_MASK_POINTERCONFINED & mask) ) { + sb.append("confined"); + } + sb.append("]"); } - if( 0 != ( STATE_MASK_POINTERCONFINED & mask) ) { - sb.append("confined"); - } - sb.append("]"); } sb.append("]"); return sb; @@ -661,15 +749,37 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } final long t0 = System.currentTimeMillis(); createNativeImpl(); + supportedReconfigStateMask = getSupportedReconfigMaskImpl() & STATE_MASK_ALL_RECONFIG; + if( DEBUG_IMPLEMENTATION) { + final boolean minimumOK = minimumReconfigStateMask == ( minimumReconfigStateMask & supportedReconfigStateMask ); + System.err.println("Supported Reconfig (minimum-ok "+minimumOK+"): "+appendStateBits(new StringBuilder(), supportedReconfigStateMask, true).toString()); + } screen.addMonitorModeListener(monitorModeListenerImpl); setTitleImpl(title); setPointerIconIntern(pointerIcon); - setPointerVisibleIntern(stateMask.get(STATE_BIT_POINTERVISIBLE)); - confinePointerImpl(stateMask.get(STATE_BIT_POINTERCONFINED)); + if( !stateMask.get(STATE_BIT_POINTERVISIBLE) ) { + // non default action + if( isReconfigureMaskSupported(STATE_MASK_POINTERVISIBLE) ) { + setPointerVisibleIntern(stateMask.get(STATE_BIT_POINTERVISIBLE)); + } else { + stateMask.set(STATE_BIT_POINTERVISIBLE); + } + } + if( stateMask.get(STATE_BIT_POINTERCONFINED) ) { + // non default action + if( isReconfigureMaskSupported(STATE_MASK_POINTERCONFINED) ) { + confinePointerImpl(true); + } else { + stateMask.clear(STATE_BIT_POINTERCONFINED); + } + } setKeyboardVisible(keyboardVisible); final long remainingV = waitForVisible(true, false); if( 0 <= remainingV ) { - if(isFullscreen()) { + if( stateMask.get(STATE_BIT_FULLSCREEN) && !isReconfigureMaskSupported(STATE_MASK_FULLSCREEN) ) { + stateMask.clear(STATE_BIT_FULLSCREEN); + } + if( stateMask.get(STATE_BIT_FULLSCREEN) ) { synchronized(fullScreenAction) { stateMask.clear(STATE_BIT_FULLSCREEN); // trigger a state change fullScreenAction.init(true); @@ -838,6 +948,17 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer protected abstract void requestFocusImpl(boolean force); /** + * Returns the reconfigure state-mask supported by the implementation. + * <p> + * Default value is {@link #STATE_MASK_VISIBLE} | {@link #STATE_MASK_FOCUSED}, + * i.e. the <b>minimum requirement</b> for all implementations. + * </p> + * @see #getSupportedStateMask() + * @see #reconfigureWindowImpl(int, int, int, int, int) + */ + protected abstract int getSupportedReconfigMaskImpl(); + + /** * The native implementation should invoke the referenced java state callbacks * to notify this Java object of state changes. * @@ -852,33 +973,33 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * @param height client-area size in window units, or <=0 if unchanged * @param flags bitfield of change and status flags * + * @see #getSupportedReconfigMaskImpl() * @see #sizeChanged(int,int) * @see #positionChanged(boolean,int, int) */ protected abstract boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags); /** - * Tests whether a single reconfigure flag is supported by implementation. - * <p> - * Default is all but {@link #STATE_MASK_FULLSCREEN_SPAN} - * </p> + * Tests whether the given reconfigure state-mask is supported by implementation. */ - protected boolean isReconfigureMaskSupported(final int changeFlags) { - return 0 == ( changeFlags & STATE_MASK_FULLSCREEN_SPAN ); + protected final boolean isReconfigureMaskSupported(final int reconfigMask) { + return reconfigMask == ( reconfigMask & supportedReconfigStateMask ); } protected int getReconfigureMask(final int changeFlags, final boolean visible) { - final int smask = stateMask.get32(0, STATE_BIT_COUNT_ALL_PUBLIC); + final int smask = stateMask.get32(0, STATE_BIT_COUNT_ALL_RECONFIG); return changeFlags - | ( smask & ~STATE_MASK_VISIBLE ) + | ( smask & ~(STATE_MASK_VISIBLE | STATE_MASK_UNDECORATED | STATE_MASK_CHILDWIN) ) | ( visible ? STATE_MASK_VISIBLE : 0 ) | ( isUndecorated(smask) ? STATE_MASK_UNDECORATED : 0 ) + | ( 0 != getParentWindowHandle() ? STATE_MASK_CHILDWIN : 0 ) ; } protected static String getReconfigStateMaskString(final int flags) { return appendStateBits(new StringBuilder(), flags, true).toString(); } + protected void setTitleImpl(final String title) {} /** @@ -896,16 +1017,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer */ protected abstract Point getLocationOnScreenImpl(int x, int y); - /** - * Triggered by user via {@link #getInsets()}.<br> - * Implementations may implement this hook to update the insets.<br> - * However, they may prefer the event driven path via {@link #insetsChanged(boolean, int, int, int, int)}. - * - * @see #getInsets() - * @see #insetsChanged(boolean, int, int, int, int) - */ - protected abstract void updateInsetsImpl(Insets insets); - protected boolean setPointerVisibleImpl(final boolean pointerVisible) { return false; } protected boolean confinePointerImpl(final boolean confine) { return false; } protected void warpPointerImpl(final int x, final int y) { } @@ -1114,9 +1225,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } reconfigureWindowImpl(x, y, width, height, mask); } + final void setVisibleActionImpl(final boolean visible) { boolean nativeWindowCreated = false; - boolean madeVisible = false; + int madeVisible = -1; final RecursiveLock _lock = windowLock; _lock.lock(); @@ -1134,16 +1246,31 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(!isNativeValid() && visible) { if( 0<getWidth()*getHeight() ) { nativeWindowCreated = createNative(); - madeVisible = nativeWindowCreated; + madeVisible = nativeWindowCreated ? 1 : -1; } // always flag visible, allowing a retry .. stateMask.set(STATE_BIT_VISIBLE); } else if(stateMask.get(STATE_BIT_VISIBLE) != visible) { if(isNativeValid()) { // Skip WM if child-window! - setVisibleImpl(visible /* visible */, isChildWindow() /* fast */, getX(), getY(), getWidth(), getHeight()); - WindowImpl.this.waitForVisible(visible, false); - madeVisible = visible; + final boolean hasVisibilityQuirk = quirks.get(QUIRK_BIT_VISIBILITY); + setVisibleImpl(visible /* visible */, hasVisibilityQuirk || isChildWindow() /* fast */, + getX(), getY(), getWidth(), getHeight()); + if( 0 > WindowImpl.this.waitForVisible(visible, false) ) { + if( !hasVisibilityQuirk ) { + quirks.set(QUIRK_BIT_VISIBILITY); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("Setting VISIBILITY QUIRK, due to setVisible("+visible+") failure"); + } + setVisibleImpl(visible /* visible */, true /* fast */, + getX(), getY(), getWidth(), getHeight()); + if( 0 <= WindowImpl.this.waitForVisible(visible, false) ) { + madeVisible = visible ? 1 : 0; + } // else: still not working .. bail out + } // else: no other remedy known .. bail out + } else { + madeVisible = visible ? 1 : 0; + } } else { stateMask.set(STATE_BIT_VISIBLE); } @@ -1175,7 +1302,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } _lock.unlock(); } - if( nativeWindowCreated || madeVisible ) { + if( nativeWindowCreated || 1==madeVisible ) { sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener } } @@ -1194,6 +1321,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final void setVisible(final boolean wait, final boolean visible) { + if( !isReconfigureMaskSupported(STATE_MASK_VISIBLE) && isNativeValid() ) { + return; + } if(DEBUG_IMPLEMENTATION) { System.err.println("Window setVisible: START ("+getThreadName()+") "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+", windowHandle "+toHexString(windowHandle)+", state "+getStateMaskString()+" -> visible "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+(null!=parentWindow)); } @@ -1270,7 +1400,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } @Override public final void setTopLevelSize(final int width, final int height) { - setSize(width - getInsets().getTotalWidth(), height - getInsets().getTotalHeight()); + final InsetsImmutable insets = getInsets(); + setSize(width - insets.getTotalWidth(), height - insets.getTotalHeight()); } private final Runnable destroyAction = new Runnable() { @@ -1782,6 +1913,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final ReparentOperation reparentWindow(final NativeWindow newParent, final int x, final int y, final int hints) { + if( !isReconfigureMaskSupported(STATE_MASK_CHILDWIN) && isNativeValid() ) { + return ReparentOperation.ACTION_INVALID; + } final ReparentAction reparentAction = new ReparentAction(newParent, x, y, hints); runOnEDTIfAvail(true, reparentAction); return reparentAction.getOp(); @@ -1843,6 +1977,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final void setUndecorated(final boolean value) { + if( isNativeValid() ) { + if( !isReconfigureMaskSupported(STATE_MASK_UNDECORATED) ) { + return; + } + if( isFullscreen() ) { + stateMaskNFS.put(STATE_MASK_UNDECORATED, value); + return; + } + } runOnEDTIfAvail(true, new DecorationAction(value)); } @Override @@ -1866,7 +2009,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer _lock.lock(); try { if( stateMask.put(STATE_BIT_ALWAYSONTOP, alwaysOnTop) != alwaysOnTop ) { - if( isNativeValid() ) { + if( isNativeValid() && !isFullscreen() ) { // Mirror pos/size so native change notification can get overwritten final int x = getX(); final int y = getY(); @@ -1890,17 +2033,22 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( isChildWindow() ) { return; // ignore for child windows } - if( isFullscreen() ) { - if( value && isAlwaysOnBottom() ) { - setAlwaysOnBottom(false); + if( isNativeValid() ) { + if( !isReconfigureMaskSupported(STATE_MASK_ALWAYSONTOP) ) { + return; } - stateMask.put(PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP, value); - } else { - if( value && isAlwaysOnBottom() ) { - setAlwaysOnBottom(false); + if( isFullscreen() ) { + if( value && isAlwaysOnBottom() ) { + setAlwaysOnBottom(false); + } + stateMaskNFS.put(STATE_BIT_ALWAYSONTOP, value); + return; } - runOnEDTIfAvail(true, new AlwaysOnTopAction(value)); } + if( value && isAlwaysOnBottom() ) { + setAlwaysOnBottom(false); + } + runOnEDTIfAvail(true, new AlwaysOnTopAction(value)); } @Override public final boolean isAlwaysOnTop() { @@ -1944,6 +2092,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( isChildWindow() ) { return; // ignore for child windows } + if( !isReconfigureMaskSupported(STATE_MASK_ALWAYSONBOTTOM) && isNativeValid() ) { + return; + } if( value && isAlwaysOnTop() ) { setAlwaysOnTop(false); } @@ -1991,11 +2142,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( isChildWindow() ) { return; // ignore for child windows } - if( isFullscreen() ) { - stateMask.put(PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE, value); - } else { - runOnEDTIfAvail(true, new ResizableAction(value)); + if( isNativeValid() ) { + if( !isReconfigureMaskSupported(STATE_MASK_RESIZABLE) ) { + return; + } + if( isFullscreen() ) { + stateMaskNFS.put(STATE_BIT_RESIZABLE, value); + return; + } } + runOnEDTIfAvail(true, new ResizableAction(value)); } @Override public final boolean isResizable() { @@ -2039,6 +2195,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( isChildWindow() ) { return; // ignore for child windows } + if( !isReconfigureMaskSupported(STATE_MASK_STICKY) && isNativeValid() ) { + return; + } runOnEDTIfAvail(true, new StickyAction(value)); } @Override @@ -2068,6 +2227,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } if( 0 != cmask ) { if( isNativeValid() ) { + final boolean focused = hasFocus(); // Mirror pos/size so native change notification can get overwritten final int x = getX(); final int y = getY(); @@ -2079,6 +2239,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer reconfigureWindowImpl(x, y, width, height, getReconfigureMask(cmask, isVisible())); display.dispatchMessagesNative(); // status up2date + + if(focused) { + requestFocusInt( 0 == parentWindowHandle /* skipFocusAction if top-level */); + } } } } finally { @@ -2088,11 +2252,24 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } @Override - public final void setMaximized(final boolean horz, final boolean vert) { - if( isChildWindow() || isFullscreen() ) { + public final void setMaximized(boolean horz, boolean vert) { + if( isNativeValid() ) { + if( horz && !isReconfigureMaskSupported(STATE_MASK_MAXIMIZED_HORZ) ) { + horz = false; + } + if( vert && !isReconfigureMaskSupported(STATE_MASK_MAXIMIZED_VERT) ) { + vert = false; + } + } + if( isChildWindow() ) { return; // ignore for child windows } - runOnEDTIfAvail(true, new MaximizeAction(horz, vert)); + if( isFullscreen() ) { + stateMaskNFS.put(STATE_BIT_MAXIMIZED_HORZ, horz); + stateMaskNFS.put(STATE_BIT_MAXIMIZED_VERT, vert); + } else { + runOnEDTIfAvail(true, new MaximizeAction(horz, vert)); + } } @Override public final boolean isMaximizedVert() { @@ -2102,6 +2279,93 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public final boolean isMaximizedHorz() { return stateMask.get(STATE_BIT_MAXIMIZED_HORZ); } + /** Triggered by implementation's WM events to update maximized window state. */ + protected final void maximizedChanged(final boolean newMaxHorz, final boolean newMaxVert) { + if( !isFullscreen() ) { + final String stateMask0 = DEBUG_IMPLEMENTATION ? getStateMaskString() : null; + final boolean changedHorz = stateMask.put(STATE_BIT_MAXIMIZED_HORZ, newMaxHorz) != newMaxHorz; + final boolean changedVert = stateMask.put(STATE_BIT_MAXIMIZED_VERT, newMaxVert) != newMaxVert; + if ( DEBUG_IMPLEMENTATION ) { + if( changedHorz || changedVert ) { + System.err.println("Window.maximizedChanged.accepted: "+stateMask0+" -> "+getStateMaskString()); + } + } + } else if( DEBUG_IMPLEMENTATION ) { + final String stateMask0 = DEBUG_IMPLEMENTATION ? getStateMaskString() : null; + final boolean changedHorz = stateMask.get(STATE_BIT_MAXIMIZED_HORZ) != newMaxHorz; + final boolean changedVert = stateMask.get(STATE_BIT_MAXIMIZED_VERT) != newMaxVert; + if( changedHorz || changedVert ) { + System.err.println("Window.maximizedChanged.ignored: "+stateMask0+" -> max["+(newMaxHorz?"":"!")+"h, "+(newMaxVert?"":"!")+"v]"); + } + } + } + /** + * Manually calculate maximized and de-maximized position and size + * not regarding a fixed taskbar etc. + * <p> + * Use only if: + * <code> + * 0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & flags ) + * </code> + * </p> + * @param flags + * @param posSize + */ + protected void reconfigMaximizedManual(final int flags, final int posSize[], final InsetsImmutable insets) { + //if( 0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & flags ) ) { + final MonitorMode mm = getMainMonitor().getCurrentMode(); + // FIXME HiDPI: Shortcut, may need to adjust if we change scaling methodology + final int mmWidth = SurfaceScaleUtils.scaleInv(mm.getRotatedWidth(), getPixelScaleX()); + final int mmHeight = SurfaceScaleUtils.scaleInv(mm.getRotatedHeight(), getPixelScaleY()); + + if( 0 != ( CHANGE_MASK_MAXIMIZED_HORZ & flags ) ) { + if( 0 != ( STATE_MASK_MAXIMIZED_HORZ & flags ) ) { + // max-h on + normPosSizeStored[0] = true; + normPosSize[0] = posSize[0]; + normPosSize[2] = posSize[2]; + posSize[0] = insets.getLeftWidth(); + posSize[2] = mmWidth - insets.getTotalWidth(); + } else { + // max-h off + normPosSizeStored[0] = false; + posSize[0] = normPosSize[0]; + posSize[2] = normPosSize[2]; + } + } + if( 0 != ( CHANGE_MASK_MAXIMIZED_VERT & flags ) ) { + if( 0 != ( STATE_MASK_MAXIMIZED_VERT & flags ) ) { + // max-v on + normPosSizeStored[1] = true; + normPosSize[1] = posSize[1]; + normPosSize[3] = posSize[3]; + posSize[1] = insets.getTopHeight(); + posSize[3] = mmHeight - insets.getTotalHeight(); + } else { + // max-v off + normPosSizeStored[1] = false; + posSize[1] = normPosSize[1]; + posSize[3] = normPosSize[3]; + } + } + //} + } + protected void resetMaximizedManual(final int posSize[]) { + if( normPosSizeStored[0] ) { + // max-h off + normPosSizeStored[0] = false; + posSize[0] = normPosSize[0]; + posSize[2] = normPosSize[2]; + } + if( normPosSizeStored[1] ) { + // max-v off + normPosSizeStored[1] = false; + posSize[1] = normPosSize[1]; + posSize[3] = normPosSize[3]; + } + } + private final int[] normPosSize = { 0, 0, 0, 0 }; + private final boolean[] normPosSizeStored = { false, false }; @Override public final String getTitle() { @@ -2124,6 +2388,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } @Override public final void setPointerVisible(final boolean pointerVisible) { + if( !isReconfigureMaskSupported(STATE_MASK_POINTERVISIBLE) && isNativeValid() ) { + return; + } if(stateMask.get(STATE_BIT_POINTERVISIBLE) != pointerVisible) { boolean setVal = 0 == getWindowHandle(); if(!setVal) { @@ -2234,6 +2501,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } @Override public final void confinePointer(final boolean confine) { + if( !isReconfigureMaskSupported(STATE_MASK_POINTERCONFINED) && isNativeValid() ) { + return; + } if(stateMask.get(STATE_BIT_POINTERCONFINED) != confine) { boolean setVal = 0 == getWindowHandle(); if(!setVal) { @@ -2265,11 +2535,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final InsetsImmutable getInsets() { - if(isUndecorated()) { + if( isUndecorated() ) { return Insets.getZero(); + } else { + return insets; } - updateInsetsImpl(insets); - return insets; } @Override @@ -2558,6 +2828,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** Internally forcing request focus on current thread */ private void requestFocusInt(final boolean skipFocusAction) { if( skipFocusAction || !focusAction() ) { + if( !isReconfigureMaskSupported(STATE_MASK_FOCUSED) ) { + return; + } if(DEBUG_IMPLEMENTATION) { System.err.println("Window.RequestFocusInt: forcing - ("+getThreadName()+"): skipFocusAction "+ skipFocusAction+", state "+getStateMaskString()+" -> focus true - windowHandle "+ @@ -2640,7 +2913,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer @Override public final void setTopLevelPosition(final int x, final int y) { - setPosition(x + getInsets().getLeftWidth(), y + getInsets().getTopHeight()); + final InsetsImmutable insets = getInsets(); + setPosition(x + insets.getLeftWidth(), y + insets.getTopHeight()); } private class FullScreenAction implements Runnable { @@ -2648,8 +2922,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private boolean init(final boolean fullscreen) { if(isNativeValid()) { - this._fullscreen = fullscreen; - return isFullscreen() != fullscreen; + if( !isReconfigureMaskSupported(STATE_MASK_FULLSCREEN) ) { + return false; + } else { + this._fullscreen = fullscreen; + return isFullscreen() != fullscreen; + } } else { stateMask.put(STATE_BIT_FULLSCREEN, fullscreen); // set current state for createNative(..) return false; @@ -2668,11 +2946,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer final int oldWidth = getWidth(); final int oldHeight = getHeight(); - int x,y,w,h; + final int x,y,w,h; final RectangleImmutable sviewport = screen.getViewportInWindowUnits(); // window units final RectangleImmutable viewport; // window units final boolean alwaysOnTopChange, resizableChange; + if(_fullscreen) { if( null == fullscreenMonitors ) { if( stateMask.get(PSTATE_BIT_FULLSCREEN_MAINMONITOR) ) { @@ -2697,32 +2976,28 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer nfs_y = oldY; nfs_width = oldWidth; nfs_height = oldHeight; - stateMask.copy(STATE_BIT_ALWAYSONTOP, PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP); - stateMask.copy(STATE_BIT_RESIZABLE, PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE); + stateMaskNFS.put32(0, 32, stateMask.get32(0, 32) & STATE_MASK_FULLSCREEN_NFS); x = viewport.getX(); y = viewport.getY(); w = viewport.getWidth(); h = viewport.getHeight(); stateMask.clear(STATE_BIT_ALWAYSONTOP); // special aontop handling for fullscreen stateMask.set(STATE_BIT_RESIZABLE); // allow fullscreen to resize to max - alwaysOnTopChange = stateMask.get(PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP); - resizableChange = !stateMask.get(PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE); + alwaysOnTopChange = stateMaskNFS.get(STATE_BIT_ALWAYSONTOP); + resizableChange = !stateMaskNFS.get(STATE_BIT_RESIZABLE); } else { + int _x,_y,_w,_h; stateMask.set(PSTATE_BIT_FULLSCREEN_MAINMONITOR); fullscreenMonitors = null; stateMask.clear(STATE_BIT_FULLSCREEN_SPAN); viewport = null; - x = nfs_x; - y = nfs_y; - w = nfs_width; - h = nfs_height; - alwaysOnTopChange = stateMask.get(PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP) != stateMask.get(STATE_BIT_ALWAYSONTOP); - // alwaysOnBottomChange = stateMask.get(PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONBOTTOM) != stateMask.get(STATE_BIT_ALWAYSONBOTTOM); - resizableChange = stateMask.get(PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE) != stateMask.get(STATE_BIT_RESIZABLE); - stateMask.copy(PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP, STATE_BIT_ALWAYSONTOP); - stateMask.copy(PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE, STATE_BIT_RESIZABLE); - stateMask.clear(PSTATE_BIT_FULLSCREEN_NFS_ALWAYSONTOP); - stateMask.set(PSTATE_BIT_FULLSCREEN_NFS_RESIZABLE); + _x = nfs_x; + _y = nfs_y; + _w = nfs_width; + _h = nfs_height; + alwaysOnTopChange = stateMaskNFS.get(STATE_BIT_ALWAYSONTOP) != stateMask.get(STATE_BIT_ALWAYSONTOP); + resizableChange = stateMaskNFS.get(STATE_BIT_RESIZABLE) != stateMask.get(STATE_BIT_RESIZABLE); + stateMask.put32(0, 32, stateMaskNFS.get32(0, 32) | ( stateMask.get32(0, 32) & ~STATE_MASK_FULLSCREEN_NFS ) ); if(null!=parentWindow) { // reset position to 0/0 within parent space @@ -2730,12 +3005,21 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer y = 0; // refit if size is bigger than parent - if( w > parentWindow.getWidth() ) { + if( _w > parentWindow.getWidth() ) { w = parentWindow.getWidth(); + } else { + w = _w; } - if( h > parentWindow.getHeight() ) { + if( _h > parentWindow.getHeight() ) { h = parentWindow.getHeight(); + } else { + h = _h; } + } else { + x = _x; + y = _y; + w = _w; + h = _h; } } @@ -2774,7 +3058,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer final int changeMask; try { { - // Enter fullscreen - Disable alwaysOnTop/alwaysOnBottom/resizableChange + // Enter fullscreen - Disable alwaysOnTop/resizableChange int cm = 0; if( alwaysOnTopChange ) { cm = CHANGE_MASK_ALWAYSONTOP; @@ -2785,11 +3069,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer changeMask = cm; } if( _fullscreen && 0 != changeMask ) { - // Enter fullscreen - Disable alwaysOnTop/alwaysOnBottom/resizableChange + // Enter fullscreen - Disable alwaysOnTop/resizableChange reconfigureWindowImpl(oldX, oldY, oldWidth, oldHeight, getReconfigureMask(changeMask, isVisible())); } stateMask.put(STATE_BIT_FULLSCREEN, _fullscreen); + // Note CHANGE_MASK_PARENTING: STATE_MASK_CHILDWIN is refined in getReconfigureMask() + // Note CHANGE_MASK_DECORATION: STATE_MASK_UNDECORATED is refined in getReconfigureMask() reconfigureWindowImpl(x, y, w, h, getReconfigureMask( ( ( null != parentWindowLocked ) ? CHANGE_MASK_PARENTING : 0 ) | CHANGE_MASK_FULLSCREEN | CHANGE_MASK_DECORATION, isVisible()) ); @@ -2989,6 +3275,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener if(animatorPaused) { lifecycleHook.resumeRenderingAction(); + animatorPaused = false; } if( hadFocus ) { requestFocus(true); @@ -3103,9 +3390,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // public final void sendMouseEvent(final short eventType, final int modifiers, - final int x, final int y, final short button, final float rotation) { + final int x, final int y, final short button, final float rotation) { doMouseEvent(false, false, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f); } + public final void enqueueMouseEvent(final boolean wait, final short eventType, final int modifiers, final int x, final int y, final short button, final float rotation) { doMouseEvent(true, wait, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f); @@ -4121,20 +4409,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } - /** Triggered by implementation's WM events to update the position. */ - protected final void minMaxSizeChanged(final int min_width, final int min_height, final int max_width, final int max_height) { - if( 0 <= min_width && 0 <= min_height && 0 <= max_width && 0 <= max_height) { - final RectangleImmutable sz = new Rectangle(min_width, min_height, max_width, max_height); - if( !minmax_size.equals(sz) ) { - stateMask.put(PSTATE_BIT_MINMAXSIZE_SET, !sz.equals(undefSize)); - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.minMaxSizeChanged: ("+getThreadName()+"): Current "+minmax_size+" -> "+sz); - } - minmax_size.set(sz); - } - } - } - /** Triggered by implementation's WM events to update the focus state. */ protected void focusChanged(final boolean defer, final boolean focusGained) { if( stateMask.get(PSTATE_BIT_FOCUS_CHANGE_BROKEN) || @@ -4183,14 +4457,31 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } if( visible != _visible ) { final String msg = "Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+_visible; - if(failFast) { + if(DEBUG_FREEZE_AT_VISIBILITY_FAILURE) { + System.err.println("XXXX: "+msg); + System.err.println("XXXX: FREEZE"); + try { + while(true) { + Thread.sleep(100); + display.dispatchMessagesNative(); // status up2date + } + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("", e); + Thread.currentThread().interrupt(); // keep state + } throw new NativeWindowException(msg); - } else if (DEBUG_IMPLEMENTATION) { - System.err.println(msg); - ExceptionUtils.dumpStack(System.err); + } else { + if(failFast) { + throw new NativeWindowException(msg); + } else { + if (DEBUG_IMPLEMENTATION) { + System.err.println(msg); + ExceptionUtils.dumpStack(System.err); + } + return -1; + } } - return -1; - } else if( 0 < remaining ){ + } else if( 0 < remaining ) { return remaining; } else { return 0; @@ -4320,18 +4611,27 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** * Triggered by implementation's WM events to update the insets. * + * @param defer + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * * @see #getInsets() * @see #updateInsetsImpl(Insets) */ protected void insetsChanged(final boolean defer, final int left, final int right, final int top, final int bottom) { if ( left >= 0 && right >= 0 && top >= 0 && bottom >= 0 ) { + final boolean changed = left != insets.getLeftWidth() || right != insets.getRightWidth() || + top != insets.getTopHeight() || bottom != insets.getBottomHeight(); + if( blockInsetsChange || isUndecorated() ) { if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.insetsChanged (defer: "+defer+"): Skip insets change "+insets+" -> "+new Insets(left, right, top, bottom)+" (blocked "+blockInsetsChange+", undecoration "+isUndecorated()+")"); + if( changed ) { + System.err.println("Window.insetsChanged (defer: "+defer+"): Skip insets change "+insets+" -> "+new Insets(left, right, top, bottom)+" (blocked "+blockInsetsChange+", undecoration "+isUndecorated()+")"); + } } - } else if ( (left != insets.getLeftWidth() || right != insets.getRightWidth() || - top != insets.getTopHeight() || bottom != insets.getBottomHeight() ) - ) { + } else if ( changed ) { if(DEBUG_IMPLEMENTATION) { System.err.println("Window.insetsChanged (defer: "+defer+"): Changed "+insets+" -> "+new Insets(left, right, top, bottom)); } @@ -4418,6 +4718,162 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } // + // Accumulated actions + // + + /** Triggered by implementation. */ + protected final void sendMouseEventRequestFocus(final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { + sendMouseEvent(eventType, modifiers, x, y, button, rotation); + requestFocus(false /* wait */); + } + /** + * Triggered by implementation's WM events to update the visibility state and send- or enqueue one mouse event + * + * @param defer + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param entranceChange -1 ignored, 0 exit, > 0 enter + * @param eventType 0 ignored, > 0 [send|enqueue]MouseEvent + * @param modifiers + * @param x + * @param y + * @param button + * @param rotation + */ + protected final void visibleChangedSendMouseEvent(final boolean defer, final int visibleChange, + final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + if( 0 < eventType ) { + if( defer ) { + enqueueMouseEvent(false /* wait */, eventType, modifiers, x, y, button, rotation); + } else { + sendMouseEvent(eventType, modifiers, x, y, button, rotation); + } + } + } + /** + * Triggered by implementation's WM events to update the content + * @param defer if true sent event later, otherwise wait until processed. + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param x dirty-region y-pos in pixel units + * @param y dirty-region x-pos in pixel units + * @param width dirty-region width in pixel units + * @param height dirty-region height in pixel units + */ + protected final void visibleChangedWindowRepaint(final boolean defer, final int visibleChange, + final int x, final int y, final int width, final int height) { + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + windowRepaint(defer, x, y, width, height); + } + /** + * Triggered by implementation's WM events to update the focus and visibility state + * + * @param defer + * @param focusChange -1 ignored, 0 unfocused, > 0 focused + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + */ + protected final void focusVisibleChanged(final boolean defer, + final int focusChange, + final int visibleChange) { + if( 0 <= focusChange ) { // ignore focus < 0 + focusChanged(defer, 0 < focusChange); + } + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + } + /** + * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. + * + * @param defer + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + */ + protected final void insetsVisibleChanged(final boolean defer, + final int left, final int right, final int top, final int bottom, + final int visibleChange) { + insetsChanged(defer, left, right, top, bottom); + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + } + /** + * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. + * + * @param defer + * @param newX + * @param newY + * @param newWidth + * @param newHeight + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * @param focusChange -1 ignored, 0 unfocused, > 0 focused + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param force + */ + protected final void sizePosInsetsFocusVisibleChanged(final boolean defer, + final int newX, final int newY, + final int newWidth, final int newHeight, + final int left, final int right, final int top, final int bottom, + final int focusChange, + final int visibleChange, + final boolean force) { + sizeChanged(defer, newWidth, newHeight, force); + positionChanged(defer, newX, newY); + insetsChanged(defer, left, right, top, bottom); + if( 0 <= focusChange ) { // ignore focus < 0 + focusChanged(defer, 0 < focusChange); + } + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + } + /** + * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. + * + * @param defer + * @param newX + * @param newY + * @param newWidth + * @param newHeight + * @param maxHorzChange -1 ignored, 0 !maximized, > 0 maximized + * @param maxVertChange -1 ignored, 0 !maximized, > 0 maximized + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param force + */ + protected final void sizePosMaxInsetsVisibleChanged(final boolean defer, + final int newX, final int newY, + final int newWidth, final int newHeight, + final int maxHorzChange, final int maxVertChange, + final int left, final int right, final int top, final int bottom, + final int visibleChange, + final boolean force) { + sizeChanged(defer, newWidth, newHeight, force); + positionChanged(defer, newX, newY); + if( 0 <= maxHorzChange && 0 <= maxVertChange ) { + maximizedChanged(0 < maxHorzChange, 0 < maxVertChange); + } + insetsChanged(defer, left, right, top, bottom); + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + } + + // // Reflection helper .. // diff --git a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java index cc71fb559..4e9273e83 100644 --- a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java +++ b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java @@ -55,41 +55,6 @@ public class NewtFactoryAWT extends NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); /** - * @deprecated Use {@link #getNativeWindow(java.awt.Component, AWTGraphicsConfiguration)} - * - * Wraps an AWT component into a {@link com.jogamp.nativewindow.NativeWindow} utilizing the {@link com.jogamp.nativewindow.NativeWindowFactory},<br> - * using a configuration agnostic dummy {@link com.jogamp.nativewindow.DefaultGraphicsConfiguration}.<br> - * <p> - * The actual wrapping implementation is {@link com.jogamp.nativewindow.awt.JAWTWindow}.<br></p> - * <p> - * Purpose of this wrapping is to access the AWT window handle,<br> - * not to actually render into it.<br> - * Hence the dummy configuration only.</p> - * - * @param awtCompObject must be of type java.awt.Component - */ - public static JAWTWindow getNativeWindow(final Object awtCompObject, final CapabilitiesImmutable capsRequested) { - if(null==awtCompObject) { - throw new NativeWindowException("Null AWT Component"); - } - if( ! (awtCompObject instanceof java.awt.Component) ) { - throw new NativeWindowException("AWT Component not a java.awt.Component"); - } - return getNativeWindow( (java.awt.Component) awtCompObject, capsRequested ); - } - - /** - * @deprecated Use {@link #getNativeWindow(java.awt.Component, AWTGraphicsConfiguration)} - * @param awtComp - * @param capsRequested - * @return - */ - public static JAWTWindow getNativeWindow(final java.awt.Component awtComp, final CapabilitiesImmutable capsRequested) { - final AWTGraphicsConfiguration awtConfig = AWTGraphicsConfiguration.create(awtComp, null, capsRequested); - return getNativeWindow(awtComp, awtConfig); - } - - /** * Wraps an AWT component into a {@link com.jogamp.nativewindow.NativeWindow} utilizing the {@link com.jogamp.nativewindow.NativeWindowFactory},<br> * using the given {@link AWTGraphicsConfiguration}. * <p> diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java index 83832eeb4..af5d08da0 100644 --- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java @@ -38,7 +38,6 @@ import com.jogamp.nativewindow.CapabilitiesImmutable; import com.jogamp.nativewindow.DefaultGraphicsScreen; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.Point; import com.jogamp.nativewindow.util.RectangleImmutable; import com.jogamp.opengl.GLCapabilitiesChooser; @@ -455,6 +454,11 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask; + } + + @Override protected final boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { boolean res = true; @@ -489,11 +493,6 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { return new Point(x,y); } - @Override - protected final void updateInsetsImpl(final Insets insets) { - // nop .. - } - //---------------------------------------------------------------------- // Virtual On-Screen Keyboard / SoftInput // diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java index 40e3bf85a..bdf78386a 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java @@ -60,13 +60,14 @@ import com.jogamp.newt.Window; @SuppressWarnings("serial") public class AWTCanvas extends Canvas { - private GraphicsDevice device; - private GraphicsConfiguration chosen; - private AWTGraphicsConfiguration awtConfig; - private volatile JAWTWindow jawtWindow=null; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle - private CapabilitiesChooser chooser=null; + private final WindowDriver driver; private final CapabilitiesImmutable capabilities; + private final CapabilitiesChooser chooser; private final UpstreamScalable upstreamScale; + private GraphicsConfiguration chosen; + private volatile GraphicsDevice device; + private volatile AWTGraphicsConfiguration awtConfig; + private volatile JAWTWindow jawtWindow=null; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle public static interface UpstreamScalable { float[] getReqPixelScale(); @@ -75,12 +76,15 @@ public class AWTCanvas extends Canvas { private boolean displayConfigChanged=false; - public AWTCanvas(final CapabilitiesImmutable capabilities, final CapabilitiesChooser chooser, final UpstreamScalable upstreamScale) { + public AWTCanvas(final WindowDriver driver, final CapabilitiesImmutable capabilities, final CapabilitiesChooser chooser, final UpstreamScalable upstreamScale) { super(); - if(null==capabilities) { throw new NativeWindowException("Capabilities null"); } + if(null==driver) { + throw new NativeWindowException("driver null"); + } + this.driver = driver; this.capabilities=capabilities; this.chooser=chooser; this.upstreamScale = upstreamScale; @@ -117,6 +121,9 @@ public class AWTCanvas extends Canvas { @Override public void addNotify() { + // before native peer is valid: X11 + disableBackgroundErase(); + /** * 'super.addNotify()' determines the GraphicsConfiguration, * while calling this class's overriden 'getGraphicsConfiguration()' method @@ -134,8 +141,7 @@ public class AWTCanvas extends Canvas { } chosen = awtConfig.getAWTGraphicsConfiguration(); - // before native peer is valid: X11 - disableBackgroundErase(); + setAWTGraphicsConfiguration(awtConfig); // issues getGraphicsConfiguration() and creates the native peer super.addNotify(); @@ -146,16 +152,20 @@ public class AWTCanvas extends Canvas { { jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig); // trigger initialization cycle - jawtWindow.setSurfaceScale(upstreamScale.getReqPixelScale() ); jawtWindow.lockSurface(); - upstreamScale.setHasPixelScale(jawtWindow.getCurrentSurfaceScale(new float[2])); - jawtWindow.unlockSurface(); + try { + jawtWindow.setSurfaceScale(upstreamScale.getReqPixelScale() ); + upstreamScale.setHasPixelScale(jawtWindow.getCurrentSurfaceScale(new float[2])); + } finally { + jawtWindow.unlockSurface(); + } } final GraphicsConfiguration gc = super.getGraphicsConfiguration(); if(null!=gc) { device = gc.getDevice(); } + driver.localCreate(); if(Window.DEBUG_IMPLEMENTATION) { System.err.println(getThreadName()+": AWTCanvas.addNotify.X"); } @@ -170,16 +180,28 @@ public class AWTCanvas extends Canvas { return null != jawtWindow ? jawtWindow.isOffscreenLayerSurfaceEnabled() : false; } + private void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config) { + // Cache awtConfig + awtConfig = config; + if( null != jawtWindow ) { + // Notify JAWTWindow .. + jawtWindow.setAWTGraphicsConfiguration(config); + } + } + @Override public void removeNotify() { + if(Window.DEBUG_IMPLEMENTATION) { + System.err.println(getThreadName()+": AWTCanvas.removeNotify.0: Created Config: "+awtConfig); + } try { - dispose(); + driver.localDestroy(); } finally { super.removeNotify(); } } - private void dispose() { + void dispose() { if( null != jawtWindow ) { jawtWindow.destroy(); if(Window.DEBUG_IMPLEMENTATION) { @@ -198,6 +220,7 @@ public class AWTCanvas extends Canvas { System.err.println(getThreadName()+": AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); } } + awtConfig = null; } private String getThreadName() { return Thread.currentThread().getName(); } @@ -255,9 +278,9 @@ public class AWTCanvas extends Canvas { * block, both devices should have the same visual list, and the * same configuration should be selected here. */ - final AWTGraphicsConfiguration config = chooseGraphicsConfiguration( + final AWTGraphicsConfiguration newConfig = chooseGraphicsConfiguration( awtConfig.getChosenCapabilities(), awtConfig.getRequestedCapabilities(), chooser, gc.getDevice()); - final GraphicsConfiguration compatible = (null!=config)?config.getAWTGraphicsConfiguration():null; + final GraphicsConfiguration compatible = (null!=newConfig)?newConfig.getAWTGraphicsConfiguration():null; if(Window.DEBUG_IMPLEMENTATION) { final Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName()); e.printStackTrace(); @@ -265,8 +288,8 @@ public class AWTCanvas extends Canvas { System.err.println("Created Config (n): THIS GC "+gc); System.err.println("Created Config (n): Choosen GC "+compatible); System.err.println("Created Config (n): HAVE CF "+awtConfig); - System.err.println("Created Config (n): Choosen CF "+config); - System.err.println("Created Config (n): EQUALS CAPS "+config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())); + System.err.println("Created Config (n): Choosen CF "+newConfig); + System.err.println("Created Config (n): EQUALS CAPS "+newConfig.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())); } if (compatible != null) { @@ -275,10 +298,10 @@ public class AWTCanvas extends Canvas { * any outside callers of this method. */ chosen = compatible; - if( !config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())) { + if( !newConfig.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())) { displayConfigChanged=true; } - awtConfig = config; + setAWTGraphicsConfiguration(newConfig); } } diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java index 9d3121635..3d9073769 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java @@ -33,6 +33,8 @@ import java.awt.EventQueue; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.RunnableTask; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.newt.util.EDTUtil; @@ -54,7 +56,7 @@ public class AWTEDTUtil implements EDTUtil { this.threadGroup = tg; this.name=Thread.currentThread().getName()+"-"+name+"-EDT-"; this.dispatchMessages=dispatchMessages; - this.nedt = new NEDT(threadGroup, name); + this.nedt = new NEDT(threadGroup, this.name); this.nedt.setDaemon(true); // don't stop JVM from shutdown .. } @@ -132,8 +134,7 @@ public class AWTEDTUtil implements EDTUtil { } private final boolean invokeImpl(boolean wait, final Runnable task, final boolean stop) { - Throwable throwable = null; - RunnableTask rTask = null; + final RunnableTask rTask; final Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution synchronized(edtLock) { // lock the EDT status @@ -150,6 +151,7 @@ public class AWTEDTUtil implements EDTUtil { task.run(); } wait = false; // running in same thread (EDT) -> no wait + rTask = null; if(stop) { nedt.shouldStop = true; } @@ -182,18 +184,21 @@ public class AWTEDTUtil implements EDTUtil { true /* always catch and report Exceptions, don't disturb EDT */, wait ? null : System.err); AWTEDTExecutor.singleton.invoke(false, rTask); + } else { + wait = false; + rTask = null; } } } if( wait ) { try { - rTaskLock.wait(); // free lock, allow execution of rTask + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); + throw new InterruptedRuntimeException(ie); } + final Throwable throwable = rTask.getThrowable(); if(null!=throwable) { if(throwable instanceof NativeWindowException) { throw (NativeWindowException)throwable; @@ -227,12 +232,12 @@ public class AWTEDTUtil implements EDTUtil { final public boolean waitUntilStopped() { synchronized(edtLock) { if( nedt.isRunning && nedt != Thread.currentThread() && !EventQueue.isDispatchThread() ) { - while( nedt.isRunning ) { - try { + try { + while( nedt.isRunning ) { edtLock.wait(); - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } return true; } else { @@ -241,13 +246,13 @@ public class AWTEDTUtil implements EDTUtil { } } - class NEDT extends Thread { + class NEDT extends InterruptSource.Thread { volatile boolean shouldStop = false; volatile boolean isRunning = false; Object sync = new Object(); public NEDT(final ThreadGroup tg, final String name) { - super(tg, name); + super(tg, null, name); } final public boolean isRunning() { @@ -286,7 +291,7 @@ public class AWTEDTUtil implements EDTUtil { try { sync.wait(pollPeriod); } catch (final InterruptedException e) { - e.printStackTrace(); + throw new InterruptedRuntimeException(e); } } } diff --git a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java index edc884366..aa93dd9aa 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java @@ -74,6 +74,8 @@ public class WindowDriver extends WindowImpl { public WindowDriver(final Container container) { super(); + this.withinLocalDispose = false; + this.addWindowListener(0, new NEWTWindowListener()); this.awtContainer = container; if(container instanceof Frame) { awtFrame = (Frame) container; @@ -85,6 +87,7 @@ public class WindowDriver extends WindowImpl { /** same instance as container, just for impl. convenience */ private Frame awtFrame = null; private AWTCanvas awtCanvas; + private volatile boolean withinLocalDispose; @Override protected void requestFocusImpl(final boolean reparented) { @@ -112,64 +115,98 @@ public class WindowDriver extends WindowImpl { @Override protected void createNativeImpl() { - if(0!=getParentWindowHandle()) { - throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead"); - } - - if(null==awtContainer) { - awtFrame = new Frame(); - awtContainer = awtFrame; - owningFrame=true; + if( withinLocalDispose ) { + setupHandleAndGC(); + definePosition(getX(), getY()); // clear AUTOPOS + visibleChanged(false, true); + withinLocalDispose = false; } else { - owningFrame=false; - defineSize(awtContainer.getWidth(), awtContainer.getHeight()); - definePosition(awtContainer.getX(), awtContainer.getY()); - } - if(null!=awtFrame) { - awtFrame.setTitle(getTitle()); - } - awtContainer.setLayout(new BorderLayout()); + if(0!=getParentWindowHandle()) { + throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead"); + } + + if(null==awtContainer) { + awtFrame = new Frame(); + awtContainer = awtFrame; + owningFrame=true; + } else { + owningFrame=false; + defineSize(awtContainer.getWidth(), awtContainer.getHeight()); + definePosition(awtContainer.getX(), awtContainer.getY()); + } + if(null!=awtFrame) { + awtFrame.setTitle(getTitle()); + } + awtContainer.setLayout(new BorderLayout()); - if( null == awtCanvas ) { - awtCanvas = new AWTCanvas(capsRequested, WindowDriver.this.capabilitiesChooser, upstreamScalable); + if( null == awtCanvas ) { + awtCanvas = new AWTCanvas(this, capsRequested, WindowDriver.this.capabilitiesChooser, upstreamScalable); - // canvas.addComponentListener(listener); - awtContainer.add(awtCanvas, BorderLayout.CENTER); + // canvas.addComponentListener(listener); + awtContainer.add(awtCanvas, BorderLayout.CENTER); - // via EDT .. - new AWTMouseAdapter(this).addTo(awtCanvas); // fwd all AWT Mouse events to here - new AWTKeyAdapter(this).addTo(awtCanvas); // fwd all AWT Key events to here + // via EDT .. + new AWTMouseAdapter(this).addTo(awtCanvas); // fwd all AWT Mouse events to here + new AWTKeyAdapter(this).addTo(awtCanvas); // fwd all AWT Key events to here - // direct w/o EDT - new AWTWindowAdapter(new LocalWindowListener(), this).addTo(awtCanvas); // fwd all AWT Window events to here + // direct w/o EDT + new AWTWindowAdapter(new AWTWindowListener(), this).addTo(awtCanvas); // fwd all AWT Window events to here + } else { + awtContainer.add(awtCanvas, BorderLayout.CENTER); + } + reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureMask(CHANGE_MASK_VISIBILITY | CHANGE_MASK_DECORATION, true)); + // throws exception if failed .. + // AWTCanvas -> localCreate -> setupHandleAndGC(); } + } - reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureMask(CHANGE_MASK_VISIBILITY | CHANGE_MASK_DECORATION, true)); - // throws exception if failed .. + private void setupHandleAndGC() { + // reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureMask(CHANGE_MASK_VISIBILITY | CHANGE_MASK_DECORATION, true)); + if( null != awtCanvas ) { + final NativeWindow nw = awtCanvas.getNativeWindow(); + if( null != nw ) { + setGraphicsConfiguration( awtCanvas.getAWTGraphicsConfiguration() ); + setWindowHandle( nw.getWindowHandle() ); + } + } + } - final NativeWindow nw = awtCanvas.getNativeWindow(); - if( null != nw ) { - setGraphicsConfiguration( awtCanvas.getAWTGraphicsConfiguration() ); - setWindowHandle( nw.getWindowHandle() ); + void localCreate() { + if( withinLocalDispose ) { + setVisible(true); + } else { + setupHandleAndGC(); } } + void localDestroy() { + this.withinLocalDispose = true; + super.destroy(); + } + @Override protected void closeNativeImpl() { setWindowHandle(0); - if(null!=awtContainer) { - awtContainer.setVisible(false); - awtContainer.remove(awtCanvas); - awtContainer.setEnabled(false); - awtCanvas.setEnabled(false); - } - if(owningFrame && null!=awtFrame) { - awtFrame.dispose(); - owningFrame=false; + if( this.withinLocalDispose ) { + if(null!=awtCanvas) { + awtCanvas.dispose(); + } + } else { + if(null!=awtContainer) { + awtContainer.setVisible(false); + awtContainer.remove(awtCanvas); + awtContainer.setEnabled(false); + awtCanvas.setEnabled(false); + awtCanvas.dispose(); + } + if(owningFrame && null!=awtFrame) { + awtFrame.dispose(); + owningFrame=false; + } + awtCanvas = null; + awtFrame = null; + awtContainer = null; } - awtCanvas = null; - awtFrame = null; - awtContainer = null; } @Override @@ -191,12 +228,6 @@ public class WindowDriver extends WindowImpl { return res; } - @Override - protected void updateInsetsImpl(final com.jogamp.nativewindow.util.Insets insets) { - final Insets contInsets = awtContainer.getInsets(); - insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom); - } - private void setCanvasSizeImpl(final int width, final int height) { final Dimension szClient = new Dimension(width, height); final java.awt.Window awtWindow = AWTMisc.getWindow(awtCanvas); @@ -231,6 +262,11 @@ public class WindowDriver extends WindowImpl { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask; + } + + @Override protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { if(DEBUG_IMPLEMENTATION) { System.err.println("AWTWindow reconfig: "+x+"/"+y+" "+width+"x"+height+", "+ @@ -250,6 +286,8 @@ public class WindowDriver extends WindowImpl { if( 0 != ( STATE_MASK_VISIBLE & flags) ) { setCanvasSizeImpl(width, height); awtContainer.setVisible( true ); + final Insets contInsets = awtContainer.getInsets(); + insetsChanged(false, contInsets.left, contInsets.right, contInsets.top, contInsets.bottom); } else { awtContainer.setVisible( false ); } @@ -265,6 +303,7 @@ public class WindowDriver extends WindowImpl { if( awtContainer.getX() != x || awtContainer.getY() != y ) { awtContainer.setLocation(x, y); } + definePosition(x, y); if( 0 != ( CHANGE_MASK_VISIBILITY & flags) ) { if( 0 != ( STATE_MASK_VISIBLE & flags ) ) { @@ -279,6 +318,9 @@ public class WindowDriver extends WindowImpl { } visibleChanged(false, 0 != ( STATE_MASK_VISIBLE & flags)); } + if( isVisible() ) { + windowRepaint(false, 0, 0, getSurfaceWidth(), getSurfaceHeight()); + } return true; } @@ -295,7 +337,7 @@ public class WindowDriver extends WindowImpl { return ( null != awtCanvas ) ? awtCanvas.getNativeWindow() : null; } - class LocalWindowListener implements com.jogamp.newt.event.WindowListener { + class AWTWindowListener implements com.jogamp.newt.event.WindowListener { @Override public void windowMoved(final com.jogamp.newt.event.WindowEvent e) { if(null!=awtContainer) { @@ -338,4 +380,28 @@ public class WindowDriver extends WindowImpl { } } } + class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { + @Override + public void windowMoved(final com.jogamp.newt.event.WindowEvent e) { } + @Override + public void windowResized(final com.jogamp.newt.event.WindowEvent e) { } + @Override + public void windowDestroyNotify(final WindowEvent e) { + if( withinLocalDispose ) { + e.setConsumed(true); + } + } + @Override + public void windowDestroyed(final WindowEvent e) { + if( withinLocalDispose ) { + e.setConsumed(true); + } + } + @Override + public void windowGainedFocus(final WindowEvent e) { } + @Override + public void windowLostFocus(final WindowEvent e) { } + @Override + public void windowRepaint(final WindowUpdateEvent e) { } + } } diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java index f20f938b6..d19618bd1 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/WindowDriver.java @@ -38,7 +38,6 @@ import com.jogamp.nativewindow.AbstractGraphicsConfiguration; import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.Point; import com.jogamp.opengl.GLCapabilitiesImmutable; @@ -94,6 +93,11 @@ public class WindowDriver extends jogamp.newt.WindowImpl { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask; + } + + @Override protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { if(0!=getWindowHandle()) { if(0 != ( CHANGE_MASK_FULLSCREEN & flags)) { @@ -128,11 +132,6 @@ public class WindowDriver extends jogamp.newt.WindowImpl { } @Override - protected void updateInsetsImpl(final Insets insets) { - // nop .. - } - - @Override public boolean surfaceSwap() { SwapWindow(getDisplayHandle(), getWindowHandle()); return true; diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java index d111e850e..d4af1b972 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java @@ -67,10 +67,12 @@ public class DisplayDriver extends DisplayImpl { PNGPixelRect image = null; if( DisplayImpl.isPNGUtilAvailable() ) { - final IOUtil.ClassResources res = new IOUtil.ClassResources(DisplayDriver.class, new String[] { "newt/data/pointer-grey-alpha-16x24.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/pointer-grey-alpha-16x24.png" }, DisplayDriver.class.getClassLoader(), null); try { final URLConnection urlConn = res.resolve(0); - image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + if( null != urlConn ) { + image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + } } catch (final Exception e) { e.printStackTrace(); } @@ -96,7 +98,11 @@ public class DisplayDriver extends DisplayImpl { aDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); aDevice.open(); - defaultPointerIcon = (PointerIconImpl) createPointerIcon(defaultPointerIconImage, 0, 0); + if( null != defaultPointerIconImage ) { + defaultPointerIcon = (PointerIconImpl) createPointerIcon(defaultPointerIconImage, 0, 0); + } else { + defaultPointerIcon = null; + } if( DEBUG_POINTER_ICON ) { System.err.println("Display.PointerIcon.createDefault: "+defaultPointerIcon); } diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java index 34212d012..b0a4ee34a 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/WindowDriver.java @@ -36,7 +36,6 @@ import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.Point; import com.jogamp.nativewindow.util.Rectangle; import com.jogamp.nativewindow.util.RectangleImmutable; @@ -249,6 +248,20 @@ public class WindowDriver extends WindowImpl { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask | + // STATE_MASK_UNDECORATED | + // STATE_MASK_ALWAYSONTOP | + // STATE_MASK_ALWAYSONBOTTOM | + // STATE_MASK_STICKY | + // STATE_MASK_RESIZABLE | + // STATE_MASK_MAXIMIZED_VERT | + // STATE_MASK_MAXIMIZED_HORZ | + STATE_MASK_POINTERVISIBLE | + STATE_MASK_POINTERCONFINED; + } + + @Override protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final int flags) { final RectangleImmutable rect = clampRect((ScreenDriver) getScreen(), new Rectangle(x, y, width, height), false); // reconfigure0 will issue position/size changed events if required @@ -263,11 +276,6 @@ public class WindowDriver extends WindowImpl { } @Override - protected void updateInsetsImpl(final Insets insets) { - // nop .. - } - - @Override protected final void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers, final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) { if( MouseEvent.EVENT_MOUSE_MOVED == eventType || MouseEvent.EVENT_MOUSE_DRAGGED == eventType ) { diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java index a083f420f..b01928449 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/WindowDriver.java @@ -35,7 +35,6 @@ package jogamp.newt.driver.intel.gdl; import com.jogamp.nativewindow.*; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.Point; public class WindowDriver extends jogamp.newt.WindowImpl { @@ -86,6 +85,11 @@ public class WindowDriver extends jogamp.newt.WindowImpl { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask; + } + + @Override protected boolean reconfigureWindowImpl(int x, int y, int width, int height, final int flags) { final ScreenDriver screen = (ScreenDriver) getScreen(); @@ -132,11 +136,6 @@ public class WindowDriver extends jogamp.newt.WindowImpl { return new Point(x,y); } - @Override - protected void updateInsetsImpl(final Insets insets) { - // nop .. - } - //---------------------------------------------------------------------- // Internals only // diff --git a/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java index 242f644f6..ce5d208db 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/kd/WindowDriver.java @@ -39,7 +39,6 @@ import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; import com.jogamp.nativewindow.VisualIDHolder.VIDType; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.Point; import com.jogamp.opengl.GLCapabilitiesImmutable; @@ -96,6 +95,11 @@ public class WindowDriver extends WindowImpl { protected void requestFocusImpl(final boolean reparented) { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask; + } + + @Override protected boolean reconfigureWindowImpl(final int x, final int y, int width, int height, final int flags) { if( 0 != ( CHANGE_MASK_VISIBILITY & flags) ) { setVisible0(eglWindowHandle, 0 != ( STATE_MASK_VISIBLE & flags)); @@ -134,11 +138,6 @@ public class WindowDriver extends WindowImpl { return new Point(x,y); } - @Override - protected void updateInsetsImpl(final Insets insets) { - // nop .. - } - //---------------------------------------------------------------------- // Internals only // diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java index bc0bfaa16..c3b7bff36 100644 --- a/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java +++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxEventDeviceTracker.java @@ -43,6 +43,7 @@ import jogamp.newt.WindowImpl; import jogamp.newt.driver.KeyTracker; import com.jogamp.common.nio.StructAccessor; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.Window; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.WindowEvent; @@ -63,7 +64,7 @@ public class LinuxEventDeviceTracker implements WindowListener, KeyTracker { static { ledt = new LinuxEventDeviceTracker(); - final Thread t = new Thread(ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager"); + final Thread t = new InterruptSource.Thread(null, ledt.eventDeviceManager, "NEWT-LinuxEventDeviceManager"); t.setDaemon(true); t.start(); } @@ -153,7 +154,7 @@ public class LinuxEventDeviceTracker implements WindowListener, KeyTracker { if(number<32&&number>=0) { if(eventDevicePollers[number]==null){ eventDevicePollers[number] = new EventDevicePoller(number); - final Thread t = new Thread(eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number); + final Thread t = new InterruptSource.Thread(null, eventDevicePollers[number], "NEWT-LinuxEventDeviceTracker-event"+number); t.setDaemon(true); t.start(); } else if(eventDevicePollers[number].stop) { diff --git a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java index f40728da0..53bb9c3a5 100644 --- a/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java +++ b/src/newt/classes/jogamp/newt/driver/linux/LinuxMouseTracker.java @@ -37,6 +37,7 @@ import java.io.InputStream; import jogamp.newt.WindowImpl; import jogamp.newt.driver.MouseTracker; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.Screen; import com.jogamp.newt.Window; import com.jogamp.newt.event.MouseEvent; @@ -55,7 +56,7 @@ public class LinuxMouseTracker implements WindowListener, MouseTracker { static { lmt = new LinuxMouseTracker(); - final Thread t = new Thread(lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker"); + final Thread t = new InterruptSource.Thread(null, lmt.mouseDevicePoller, "NEWT-LinuxMouseTracker"); t.setDaemon(true); t.start(); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java index c8146b85d..8ff37872b 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java @@ -70,7 +70,9 @@ public class DisplayDriver extends DisplayImpl { // NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly! final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons(); final URLConnection urlConn = iconRes.resolve(iconRes.resourceCount()-1); - image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.RGBA8888, true /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + if( null != urlConn ) { + image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.RGBA8888, true /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + } } catch (final Exception e) { e.printStackTrace(); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java index 0d144775a..46c86d2c1 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java @@ -34,6 +34,7 @@ package jogamp.newt.driver.macosx; +import com.jogamp.common.util.InterruptSource; import com.jogamp.nativewindow.AbstractGraphicsConfiguration; import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.NativeWindow; @@ -41,8 +42,6 @@ import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.MutableSurface; import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.util.Insets; -import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.nativewindow.util.Point; import com.jogamp.nativewindow.util.PointImmutable; @@ -54,7 +53,6 @@ import jogamp.newt.WindowImpl; import jogamp.newt.driver.DriverClearFocus; import jogamp.newt.driver.DriverUpdatePosition; -import com.jogamp.newt.MonitorMode; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.MonitorEvent; @@ -121,11 +119,10 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl /** Called from native code */ protected void updatePixelScale(final boolean defer, final float newPixelScaleRaw, final float maxPixelScaleRaw) { - final long handle = getWindowHandle(); if( DEBUG_IMPLEMENTATION ) { - System.err.println("WindowDriver.updatePixelScale.3: "+hasPixelScale[0]+" (has) -> "+newPixelScaleRaw+" (new), "+maxPixelScaleRaw+" (max), drop "+(0==handle)); + System.err.println("WindowDriver.updatePixelScale.3: "+hasPixelScale[0]+" (has) -> "+newPixelScaleRaw+" (new), "+maxPixelScaleRaw+" (max), drop "+!isNativeValid()); } - if( 0 != handle ) { + if( isNativeValid() ) { updatePixelScale(true /* sendEvent*/, defer, true /*offthread */, newPixelScaleRaw, maxPixelScaleRaw); } } @@ -199,7 +196,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl } setGraphicsConfiguration(cfg); reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureMask(CHANGE_MASK_VISIBILITY, true)); - if (0 == getWindowHandle()) { + if ( !isNativeValid() ) { throw new NativeWindowException("Error creating window"); } } @@ -214,6 +211,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl surfaceHandle = 0; sscSurfaceHandle = 0; isOffscreenInstance = false; + resizeAnimatorPaused = false; if (0 != handle) { OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { @Override @@ -271,7 +269,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl System.err.println("MacWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); } sscSurfaceHandle = surfaceHandle; - if (isNativeValid()) { + if ( isNativeValid() ) { if (0 != sscSurfaceHandle) { OSXUtil.RunOnMainThread(false, false, new Runnable() { @Override @@ -343,15 +341,20 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl if( 0 != handle && !isOffscreenInstance ) { final NativeWindow parent = getParent(); final boolean useParent = useParent(parent); - final int pX=parent.getX(), pY=parent.getY(); - final Point p0S = getLocationOnScreenImpl(x, y, parent, useParent); + final Point p0S; + if( useParent ) { + p0S = getLocationOnScreenByParent(x, y, parent); + } else { + p0S = (Point) getLocationOnScreen0(handle, x, y); + } if(DEBUG_IMPLEMENTATION) { + final int pX=parent.getX(), pY=parent.getY(); System.err.println("MacWindow: updatePosition() parent["+useParent+" "+pX+"/"+pY+"] "+x+"/"+y+" -> "+x+"/"+y+" rel-client-pos, "+p0S+" screen-client-pos"); } OSXUtil.RunOnMainThread(false, false, new Runnable() { @Override public void run() { - setWindowClientTopLeftPoint0(handle, p0S.getX(), p0S.getY(), isVisible()); + setWindowClientTopLeftPoint0(getWindowHandle(), p0S.getX(), p0S.getY(), isVisible()); } } ); // no native event (fullscreen, some reparenting) positionChanged(true, x, y); @@ -359,39 +362,20 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl } @Override - protected void sizeChanged(final boolean defer, final int newWidth, final int newHeight, final boolean force) { - final long handle = getWindowHandle(); - if( 0 != handle && !isOffscreenInstance ) { - final NativeWindow parent = getParent(); - final boolean useParent = useParent(parent); - if( useParent && ( getWidth() != newWidth || getHeight() != newHeight ) ) { - final int x=getX(), y=getY(); - final Point p0S = getLocationOnScreenImpl(x, y, parent, useParent); - if(DEBUG_IMPLEMENTATION) { - System.err.println("MacWindow: sizeChanged() parent["+useParent+" "+x+"/"+y+"] "+getX()+"/"+getY()+" "+newWidth+"x"+newHeight+" -> "+p0S+" screen-client-pos"); - } - OSXUtil.RunOnMainThread(false, false, new Runnable() { - @Override - public void run() { - setWindowClientTopLeftPoint0(getWindowHandle(), p0S.getX(), p0S.getY(), isVisible()); - } } ); - } - } - superSizeChangedOffThread(defer, newWidth, newHeight, force); - } - private void superSizeChangedOffThread(final boolean defer, final int newWidth, final int newHeight, final boolean force) { - if( defer ) { - new Thread() { - public void run() { - WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force); - } }.start(); - } else { - WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force); - } + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask | + STATE_MASK_CHILDWIN | + STATE_MASK_UNDECORATED | + STATE_MASK_ALWAYSONTOP | + STATE_MASK_ALWAYSONBOTTOM | + STATE_MASK_STICKY | + STATE_MASK_RESIZABLE | + STATE_MASK_MAXIMIZED_VERT | + STATE_MASK_MAXIMIZED_HORZ | + STATE_MASK_POINTERVISIBLE | + STATE_MASK_POINTERCONFINED; } - private final int[] normPosSize = { 0, 0, 0, 0 }; - @Override protected boolean reconfigureWindowImpl(int _x, int _y, int _width, int _height, final int flags) { final boolean _isOffscreenInstance = isOffscreenInstance(this, this.getParent()); @@ -402,43 +386,16 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl pClientLevelOnSreen = new Point(0, 0); } else { final NativeWindow parent = getParent(); - final boolean useParent = useParent(parent); - if( useParent ) { - pClientLevelOnSreen = getLocationOnScreenImpl(_x, _y, parent, useParent); + if( useParent(parent) ) { + pClientLevelOnSreen = getLocationOnScreenByParent(_x, _y, parent); } else { if( 0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & flags ) ) { - final InsetsImmutable insets = getInsets(); - final MonitorMode mm = getMainMonitor().getCurrentMode(); - // FIXME HiDPI: Shortcut, may need to adjust if we change scaling methodology - final int mmWidth = SurfaceScaleUtils.scaleInv(mm.getRotatedWidth(), getPixelScaleX()); - final int mmHeight = SurfaceScaleUtils.scaleInv(mm.getRotatedHeight(), getPixelScaleY()); - - if( 0 != ( CHANGE_MASK_MAXIMIZED_HORZ & flags ) ) { - if( 0 != ( STATE_MASK_MAXIMIZED_HORZ & flags ) ) { - // max-h on - normPosSize[0] = _x; - normPosSize[2] = _width; - _x = insets.getLeftWidth(); - _width = mmWidth - insets.getTotalWidth(); - } else { - // max-h off - _x = normPosSize[0]; - _width = normPosSize[2]; - } - } - if( 0 != ( CHANGE_MASK_MAXIMIZED_VERT & flags ) ) { - if( 0 != ( STATE_MASK_MAXIMIZED_VERT & flags ) ) { - // max-v on - normPosSize[1] = _y; - normPosSize[3] = _height; - _y = insets.getTopHeight(); - _height = mmHeight - insets.getTotalHeight(); - } else { - // max-h off - _y = normPosSize[1]; - _height = normPosSize[3]; - } - } + final int[] posSize = { _x, _y, _width, _height }; + reconfigMaximizedManual(flags, posSize, getInsets()); + _x = posSize[0]; + _y = posSize[1]; + _width = posSize[2]; + _height = posSize[3]; } pClientLevelOnSreen = new Point(_x, _y); } @@ -452,7 +409,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl final AbstractGraphicsConfiguration cWinCfg = this.getGraphicsConfiguration(); final NativeWindow pWin = getParent(); final AbstractGraphicsConfiguration pWinCfg = null != pWin ? pWin.getGraphicsConfiguration() : null; - System.err.println("MacWindow reconfig.0: "+x+"/"+y+" -> clientPos "+pClientLevelOnSreen+" - "+width+"x"+height+ + System.err.println("MacWindow reconfig.0: "+x+"/"+y+" -> clientPosOnScreen "+pClientLevelOnSreen+" - "+width+"x"+height+ ", "+getReconfigStateMaskString(flags)+ ",\n\t parent type "+(null != pWin ? pWin.getClass().getName() : null)+ ",\n\t this-chosenCaps "+(null != cWinCfg ? cWinCfg.getChosenCapabilities() : null)+ @@ -477,38 +434,47 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl visibleChanged(true, false); } } - if( ( 0 == getWindowHandle() && 0 != ( STATE_MASK_VISIBLE & flags) ) || + final long oldWindowHandle = getWindowHandle(); + if( ( 0 == oldWindowHandle && 0 != ( STATE_MASK_VISIBLE & flags) ) || 0 != ( CHANGE_MASK_PARENTING & flags) || 0 != ( CHANGE_MASK_DECORATION & flags) || + 0 != ( CHANGE_MASK_ALWAYSONTOP & flags) || + 0 != ( CHANGE_MASK_ALWAYSONBOTTOM & flags) || 0 != ( CHANGE_MASK_RESIZABLE & flags) || 0 != ( CHANGE_MASK_FULLSCREEN & flags) ) { if(isOffscreenInstance) { - createWindow(true, 0 != getWindowHandle(), pClientLevelOnSreen, 64, 64, flags); + createWindow(true, 0 != oldWindowHandle, pClientLevelOnSreen, 64, 64, flags); } else { - createWindow(false, 0 != getWindowHandle(), pClientLevelOnSreen, width, height, flags); + createWindow(false, 0 != oldWindowHandle, pClientLevelOnSreen, width, height, flags); } // no native event (fullscreen, some reparenting) - positionChanged(false, x, y); updatePixelScaleByWindowHandle(false /* sendEvent */); - super.sizeChanged(false, width, height, true); + if( isOffscreenInstance) { + super.sizeChanged(false, width, height, true); + positionChanged(false, x, y); + } else { + updateSizePosInsets0(getWindowHandle(), false); + } visibleChanged(false, 0 != ( STATE_MASK_VISIBLE & flags)); if( hasFocus ) { requestFocusImpl(true); } - } else { + } else if( 0 != oldWindowHandle ) { if( width>0 && height>0 ) { if( !isOffscreenInstance ) { OSXUtil.RunOnMainThread(true, false, new Runnable() { @Override public void run() { - setWindowClientTopLeftPointAndSize0(getWindowHandle(), + setWindowClientTopLeftPointAndSize0(oldWindowHandle, pClientLevelOnSreen.getX(), pClientLevelOnSreen.getY(), width, height, 0 != ( STATE_MASK_VISIBLE & flags)); } } ); - } // else offscreen size is realized via recreation - // no native event (fullscreen, some reparenting) - positionChanged(true, x, y); - super.sizeChanged(true, width, height, false); + updateSizePosInsets0(oldWindowHandle, false); + } else { // else offscreen size is realized via recreation + // no native event (fullscreen, some reparenting) + super.sizeChanged(false, width, height, false); + positionChanged(false, x, y); + } } if( 0 != ( CHANGE_MASK_VISIBILITY & flags) && 0 != ( STATE_MASK_VISIBLE & flags) ) @@ -524,13 +490,11 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl visibleChanged(true, true); } } - if( !isOffscreenInstance ) { - setAlwaysOnTop0(getWindowHandle(), 0 != ( STATE_MASK_ALWAYSONTOP & flags)); - setAlwaysOnBottom0(getWindowHandle(), 0 != ( STATE_MASK_ALWAYSONBOTTOM & flags)); - } + } else { + throw new InternalError("Null windowHandle but no re-creation triggered, check visibility: "+getStateMaskString()); } if(DEBUG_IMPLEMENTATION) { - System.err.println("MaxWindow reconfig.X: "+getLocationOnScreenImpl(0, 0)+" "+getWidth()+"x"+getHeight()+", insets "+getInsets()+", "+getStateMaskString()); + System.err.println("MacWindow reconfig.X: "+getLocationOnScreenImpl(0, 0)+" "+getWidth()+"x"+getHeight()+", insets "+getInsets()+", "+getStateMaskString()); } return true; } @@ -538,46 +502,50 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl @Override protected Point getLocationOnScreenImpl(final int x, final int y) { final NativeWindow parent = getParent(); - final boolean useParent = useParent(parent); - return getLocationOnScreenImpl(x, y, parent, useParent); - } - - private Point getLocationOnScreenImpl(final int x, final int y, final NativeWindow parent, final boolean useParent) { - if( !useParent && !isOffscreenInstance && 0 != surfaceHandle) { - return OSXUtil.GetLocationOnScreen(surfaceHandle, x, y); - } - - final Point p = new Point(x, y); - if( useParent ) { - p.translate( parent.getLocationOnScreen(null) ); + if( useParent(parent) ) { + return getLocationOnScreenByParent(x, y, parent); + } else { + final long windowHandle = getWindowHandle(); + if( !isOffscreenInstance && 0 != windowHandle ) { + return (Point) getLocationOnScreen0(windowHandle, x, y); + } else { + return new Point(x, y); + } } - return p; } - @Override - protected void updateInsetsImpl(final Insets insets) { - // nop - using event driven insetsChange(..) + private Point getLocationOnScreenByParent(final int x, final int y, final NativeWindow parent) { + return new Point(x, y).translate( parent.getLocationOnScreen(null) ); } /** Callback for native screen position change event of the client area. */ protected void screenPositionChanged(final boolean defer, final int newX, final int newY) { // passed coordinates are in screen position of the client area - if(getWindowHandle()!=0) { + if( isNativeValid() ) { final NativeWindow parent = getParent(); - if( null == parent || isOffscreenInstance ) { + if( !useParent(parent) || isOffscreenInstance ) { if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.positionChanged.0 (Screen Pos - TOP): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY); } positionChanged(defer, newX, newY); } else { - // screen position -> rel child window position - final Point absPos = new Point(newX, newY); - final Point parentOnScreen = parent.getLocationOnScreen(null); - absPos.translate( parentOnScreen.scale(-1, -1) ); - if(DEBUG_IMPLEMENTATION) { - System.err.println("MacWindow.positionChanged.1 (Screen Pos - CHILD): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> absPos "+newX+"/"+newY+", parentOnScreen "+parentOnScreen+" -> "+absPos); + final Runnable action = new Runnable() { + public void run() { + // screen position -> rel child window position + final Point absPos = new Point(newX, newY); + final Point parentOnScreen = parent.getLocationOnScreen(null); + absPos.translate( parentOnScreen.scale(-1, -1) ); + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.positionChanged.1 (Screen Pos - CHILD): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> absPos "+newX+"/"+newY+", parentOnScreen "+parentOnScreen+" -> "+absPos); + } + positionChanged(false, absPos.getX(), absPos.getY()); + } }; + if( defer ) { + new InterruptSource.Thread(null, action).start(); + } else { + action.run(); } - positionChanged(defer, absPos.getX(), absPos.getY()); + } } else if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.positionChanged.2 (Screen Pos - IGN): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY); @@ -585,6 +553,65 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl } @Override + protected void sizeChanged(final boolean defer, final int newWidth, final int newHeight, final boolean force) { + if(force || getWidth() != newWidth || getHeight() != newHeight) { + if( isNativeValid() && !isOffscreenInstance ) { + final NativeWindow parent = getParent(); + final boolean useParent = useParent(parent); + if( useParent ) { + final int x=getX(), y=getY(); + final Point p0S = getLocationOnScreenByParent(x, y, parent); + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: sizeChanged() parent["+useParent+" "+x+"/"+y+"] "+getX()+"/"+getY()+" "+newWidth+"x"+newHeight+" -> "+p0S+" screen-client-pos"); + } + OSXUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + setWindowClientTopLeftPoint0(getWindowHandle(), p0S.getX(), p0S.getY(), isVisible()); + } } ); + } + } + superSizeChangedOffThread(defer, newWidth, newHeight, force); + } + } + private void superSizeChangedOffThread(final boolean defer, final int newWidth, final int newHeight, final boolean force) { + if( defer ) { + new InterruptSource.Thread() { + public void run() { + WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force); + } }.start(); + } else { + WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force); + } + } + + // + // Accumulated actions + // + + /** Triggered by implementation's WM events to update the client-area position, size and insets. */ + protected void sizeScreenPosInsetsChanged(final boolean defer, + final int newX, final int newY, + final int newWidth, final int newHeight, + final int left, final int right, final int top, final int bottom, + final boolean force, + final boolean withinLiveResize) { + final LifecycleHook lh = getLifecycleHook(); + if( withinLiveResize && !resizeAnimatorPaused && null!=lh ) { + resizeAnimatorPaused = lh.pauseRenderingAction(); + } + sizeChanged(defer, newWidth, newHeight, force); + screenPositionChanged(defer, newX, newY); + insetsChanged(defer, left, right, top, bottom); + if( !withinLiveResize && resizeAnimatorPaused ) { + resizeAnimatorPaused = false; + if( null!=lh ) { + lh.resumeRenderingAction(); + } + } + } + + @Override protected void setPointerIconImpl(final PointerIconImpl pi) { if( !isOffscreenInstance ) { final long piHandle = null != pi ? pi.validatedHandle() : 0; @@ -688,10 +715,7 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl protected int getDisplayID() { if( !isOffscreenInstance ) { - final long whandle = getWindowHandle(); - if(0 != whandle) { - return getDisplayID0(whandle); - } + return getDisplayID0(getWindowHandle()); } return 0; } @@ -767,14 +791,14 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl public void run() { initWindow0( parentWinHandle, newWin, pS.getX(), pS.getY(), width, height, reqPixelScale[0] /* HiDPI uniformPixelScale */, isOpaque, + !offscreenInstance && 0 != ( STATE_MASK_ALWAYSONTOP & flags), + !offscreenInstance && 0 != ( STATE_MASK_ALWAYSONBOTTOM & flags), !offscreenInstance && 0 != ( STATE_MASK_VISIBLE & flags), surfaceHandle); if( offscreenInstance ) { orderOut0(0!=parentWinHandle ? parentWinHandle : newWin); } else { setTitle0(newWin, getTitle()); - setAlwaysOnTop0(getWindowHandle(), 0 != ( STATE_MASK_ALWAYSONTOP & flags)); - setAlwaysOnBottom0(getWindowHandle(), 0 != ( STATE_MASK_ALWAYSONBOTTOM & flags)); } } }); } catch (final Exception ie) { @@ -787,7 +811,8 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl private native long createWindow0(int x, int y, int w, int h, boolean fullscreen, int windowStyle, int backingStoreType, long view); /** Must be called on Main-Thread */ private native void initWindow0(long parentWindow, long window, int x, int y, int w, int h, float reqPixelScale, - boolean opaque, boolean visible, long view); + boolean opaque, boolean atop, boolean abottom, boolean visible, long view); + private native int getDisplayID0(long window); private native void setPixelScale0(long window, long view, float reqPixelScale); private native boolean lockSurface0(long window, long view); @@ -811,10 +836,8 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl private native void setWindowClientTopLeftPointAndSize0(long window, int x, int y, int w, int h, boolean display); /** Must be called on Main-Thread */ private native void setWindowClientTopLeftPoint0(long window, int x, int y, boolean display); - /** Must be called on Main-Thread */ - private native void setAlwaysOnTop0(long window, boolean atop); - /** Must be called on Main-Thread */ - private native void setAlwaysOnBottom0(long window, boolean abottom); + /** Triggers {@link #sizeScreenPosInsetsChanged(boolean, int, int, int, int, int, int, int, int, boolean)} */ + private native void updateSizePosInsets0(long window, boolean defer); private static native Object getLocationOnScreen0(long windowHandle, int src_x, int src_y); private static native void setPointerIcon0(long windowHandle, long handle); private static native void setPointerVisible0(long windowHandle, boolean hasFocus, boolean visible); @@ -836,5 +859,5 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl private volatile long surfaceHandle = 0; private long sscSurfaceHandle = 0; private boolean isOffscreenInstance = false; - + private boolean resizeAnimatorPaused = false; } diff --git a/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java index f9f1f13ad..f7d6b9f25 100644 --- a/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java +++ b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java @@ -46,9 +46,17 @@ public class JoglUtilPNGIcon { data_size[0] = 0; for(int i=0; i<resources.resourceCount(); i++) { final URLConnection urlConn = resources.resolve(i); - final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); - data_size[0] += 2 + image.getSize().getWidth() * image.getSize().getHeight(); - images[i] = image; + if( null != urlConn ) { + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + data_size[0] += 2 + image.getSize().getWidth() * image.getSize().getHeight(); + images[i] = image; + } else { + images[i] = null; + } + } + if( 0 == data_size[0] ) { + // no image, abort + return null; } final boolean is64Bit = Platform.is64Bit(); elem_bytesize[0] = is64Bit ? Buffers.SIZEOF_LONG : Buffers.SIZEOF_INT; @@ -56,29 +64,31 @@ public class JoglUtilPNGIcon { for(int i=0; i<images.length; i++) { final PNGPixelRect image1 = images[i]; - final int width = image1.getSize().getWidth(); - final int height = image1.getSize().getHeight(); - if( is64Bit ) { - buffer.putLong(width); - buffer.putLong(height); - } else { - buffer.putInt(width); - buffer.putInt(height); - } - final ByteBuffer bb = image1.getPixels(); - final int stride = image1.getStride(); - for(int y=0; y<height; y++) { - int bbOff = y * stride; - for(int x=0; x<width; x++) { - long pixel; - pixel = ( 0xffL & bb.get(bbOff++) ); // B - pixel |= ( 0xffL & bb.get(bbOff++) ) << 8; // G - pixel |= ( 0xffL & bb.get(bbOff++) ) << 16; // R - pixel |= ( 0xffL & bb.get(bbOff++) ) << 24; // A - if( is64Bit ) { - buffer.putLong(pixel); - } else { - buffer.putInt((int)pixel); + if( null != image1 ) { + final int width = image1.getSize().getWidth(); + final int height = image1.getSize().getHeight(); + if( is64Bit ) { + buffer.putLong(width); + buffer.putLong(height); + } else { + buffer.putInt(width); + buffer.putInt(height); + } + final ByteBuffer bb = image1.getPixels(); + final int stride = image1.getStride(); + for(int y=0; y<height; y++) { + int bbOff = y * stride; + for(int x=0; x<width; x++) { + long pixel; + pixel = ( 0xffL & bb.get(bbOff++) ); // B + pixel |= ( 0xffL & bb.get(bbOff++) ) << 8; // G + pixel |= ( 0xffL & bb.get(bbOff++) ) << 16; // R + pixel |= ( 0xffL & bb.get(bbOff++) ) << 24; // A + if( is64Bit ) { + buffer.putLong(pixel); + } else { + buffer.putInt((int)pixel); + } } } } diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java index c44aa39f4..0bd7c5b2a 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java @@ -68,19 +68,23 @@ public class DisplayDriver extends DisplayImpl { final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons(); { final URLConnection urlConn = iconRes.resolve(0); - final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); - _defaultIconHandle[0] = DisplayDriver.createBGRA8888Icon0(image.getPixels(), image.getSize().getWidth(), image.getSize().getHeight(), false, 0, 0); + if( null != urlConn ) { + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + _defaultIconHandle[0] = DisplayDriver.createBGRA8888Icon0(image.getPixels(), image.getSize().getWidth(), image.getSize().getHeight(), false, 0, 0); + } } { final URLConnection urlConn = iconRes.resolve(iconRes.resourceCount()-1); - final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); - _defaultIconHandle[1] = DisplayDriver.createBGRA8888Icon0(image.getPixels(), image.getSize().getWidth(), image.getSize().getHeight(), false, 0, 0); + if( null != urlConn ) { + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + _defaultIconHandle[1] = DisplayDriver.createBGRA8888Icon0(image.getPixels(), image.getSize().getWidth(), image.getSize().getHeight(), false, 0, 0); + } } } catch (final Exception e) { e.printStackTrace(); } } - defaultIconHandles = _defaultIconHandle; + defaultIconHandles = _defaultIconHandle; // null is a valid value for an icon handle } sharedClassFactory = new RegisteredClassFactory(newtClassBaseName, WindowDriver.getNewtWndProc0(), false /* useDummyDispatchThread */, defaultIconHandles[0], defaultIconHandles[1]); diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java index 6f2660358..af5dad3ac 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java @@ -45,7 +45,6 @@ import com.jogamp.nativewindow.AbstractGraphicsConfiguration; import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.VisualIDHolder; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.nativewindow.util.Point; @@ -141,17 +140,34 @@ public class WindowDriver extends WindowImpl { } setGraphicsConfiguration(cfg); final VersionNumber winVer = Platform.getOSVersionNumber(); - final int flags = getReconfigureMask(0, true) & STATE_MASK_CREATENATIVE; + int flags = getReconfigureMask(0, true) & STATE_MASK_CREATENATIVE; + int maxCount = 0; + if( 0 != ( STATE_MASK_MAXIMIZED_HORZ & flags ) ) { + flags |= CHANGE_MASK_MAXIMIZED_HORZ; + maxCount++; + } + if( 0 != ( STATE_MASK_MAXIMIZED_VERT & flags ) ) { + flags |= CHANGE_MASK_MAXIMIZED_VERT; + maxCount++; + } final long _windowHandle = CreateWindow0(DisplayDriver.getHInstance(), display.getWindowClassName(), display.getWindowClassName(), winVer.getMajor(), winVer.getMinor(), getParentWindowHandle(), - getX(), getY(), getWidth(), getHeight(), autoPosition(), flags); + getX(), getY(), getWidth(), getHeight(), flags); if ( 0 == _windowHandle ) { throw new NativeWindowException("Error creating window"); } + if( !cfg.getChosenCapabilities().isBackgroundOpaque() ) { + GDIUtil.DwmSetupTranslucency(_windowHandle, true); + } + InitWindow0(_windowHandle, flags); setWindowHandle(_windowHandle); windowHandleClose = _windowHandle; + if( 0 == ( STATE_MASK_CHILDWIN & flags ) && 1 == maxCount ) { + reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), flags); + } + if(DEBUG_IMPLEMENTATION) { final Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+ " (Parent HWND "+toHexString(getParentWindowHandle())+ @@ -188,26 +204,51 @@ public class WindowDriver extends WindowImpl { } @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask | + STATE_MASK_CHILDWIN | + STATE_MASK_UNDECORATED | + STATE_MASK_ALWAYSONTOP | + STATE_MASK_ALWAYSONBOTTOM | + // STATE_MASK_STICKY | + STATE_MASK_RESIZABLE | + STATE_MASK_MAXIMIZED_VERT | + STATE_MASK_MAXIMIZED_HORZ | + STATE_MASK_POINTERVISIBLE | + STATE_MASK_POINTERCONFINED; + } + + @Override protected boolean reconfigureWindowImpl(int x, int y, int width, int height, final int flags) { if(DEBUG_IMPLEMENTATION) { System.err.println("WindowsWindow reconfig.0: "+x+"/"+y+" "+width+"x"+height+ ", "+getReconfigStateMaskString(flags)); } - - if(0 == ( STATE_MASK_UNDECORATED & flags)) { - final InsetsImmutable i = getInsets(); - - // client position -> top-level window position - x -= i.getLeftWidth() ; - y -= i.getTopHeight() ; - - if(0<width && 0<height) { - // client size -> top-level window size - width += i.getTotalWidth(); - height += i.getTotalHeight(); + final InsetsImmutable insets = getInsets(); + + if( 0 == ( STATE_MASK_CHILDWIN & flags ) && + 0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & flags ) ) { + final int[] posSize = { x, y, width, height }; + if( ( 0 != ( STATE_MASK_MAXIMIZED_HORZ & flags ) ) == ( 0 != ( STATE_MASK_MAXIMIZED_VERT & flags ) ) ) { + resetMaximizedManual(posSize); // reset before native maximize/reset + } else { + reconfigMaximizedManual(flags, posSize, insets); } + x = posSize[0]; + y = posSize[1]; + width = posSize[2]; + height = posSize[3]; + } + + final boolean changeDecoration = 0 != ( CHANGE_MASK_DECORATION & flags); + final boolean isTranslucent = !getChosenCapabilities().isBackgroundOpaque(); + if( changeDecoration && isTranslucent ) { + GDIUtil.DwmSetupTranslucency(getWindowHandle(), false); } reconfigureWindow0( getParentWindowHandle(), getWindowHandle(), x, y, width, height, flags); + if( changeDecoration && isTranslucent ) { + GDIUtil.DwmSetupTranslucency(getWindowHandle(), true); + } if( 0 != ( CHANGE_MASK_VISIBILITY & flags) ) { visibleChanged(false, 0 != ( STATE_MASK_VISIBLE & flags)); @@ -279,11 +320,6 @@ public class WindowDriver extends WindowImpl { return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } - @Override - protected void updateInsetsImpl(final Insets insets) { - // nop - using event driven insetsChange(..) - } - // // PointerEvent Handling // @@ -372,7 +408,8 @@ public class WindowDriver extends WindowImpl { protected static native boolean initIDs0(long hInstance); private native long CreateWindow0(long hInstance, String wndClassName, String wndName, int winMajor, int winMinor, - long parentWindowHandle, int x, int y, int width, int height, boolean autoPosition, int flags); + long parentWindowHandle, int x, int y, int width, int height, int flags); + private native void InitWindow0(long windowHandle, 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/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index d0026deaf..9e1d2869b 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -46,7 +46,6 @@ import jogamp.newt.driver.PNGIcon; import com.jogamp.nativewindow.*; import com.jogamp.nativewindow.VisualIDHolder.VIDType; -import com.jogamp.nativewindow.util.Insets; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.nativewindow.util.Point; @@ -134,7 +133,7 @@ public class WindowDriver extends WindowImpl { if (null == handles || 2 != handles.length || 0 == handles[0] || 0 == handles[1] ) { throw new NativeWindowException("Error creating window"); } - if(DEBUG_IMPLEMENTATION) { // FIXME + if(DEBUG_IMPLEMENTATION) { System.err.println("X11Window.createNativeImpl() handles "+toHexString(handles[0])+", "+toHexString(handles[1])); } setWindowHandle(handles[0]); @@ -169,15 +168,9 @@ public class WindowDriver extends WindowImpl { } } - /** - * <p> - * X11 Window supports {@link #FLAG_IS_FULLSCREEN_SPAN} - * </p> - * {@inheritDoc} - */ @Override - protected boolean isReconfigureMaskSupported(final int changeFlags) { - return true; // all flags! + protected final int getSupportedReconfigMaskImpl() { + return ( minimumReconfigStateMask | GetSupportedReconfigMask0(javaWindowHandle) ) & STATE_MASK_ALL_RECONFIG; } @Override @@ -347,11 +340,6 @@ public class WindowDriver extends WindowImpl { } @Override - protected void updateInsetsImpl(final Insets insets) { - // nop - using event driven insetsChange(..) - } - - @Override protected final void doMouseEvent(final boolean enqueue, final boolean wait, short eventType, int modifiers, final int x, final int y, short button, final float[] rotationXYZ, final float rotationScale) { switch(eventType) { @@ -458,12 +446,12 @@ public class WindowDriver extends WindowImpl { int x, int y, int width, int height, int flags, int pixelDataSize, Object pixels, int pixels_byte_offset, boolean pixels_is_direct, boolean verbose); - private native long GetNativeWindowHandle0(long javaWindowHandle); + private static native int GetSupportedReconfigMask0(long javaWindowHandle); private native void CloseWindow0(long display, long javaWindowHandle /*, long kbdHandle*/, // XKB disabled for now final int randr_event_base, final int randr_error_base); - private native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long javaWindowHandle, - int x, int y, int width, int height, int flags); - private native void requestFocus0(long display, long javaWindowHandle, boolean force); + private static native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long javaWindowHandle, + int x, int y, int width, int height, int flags); + private static native void requestFocus0(long display, long javaWindowHandle, boolean force); private static native void setTitle0(long display, long javaWindowHandle, String title); diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11UnderlayTracker.java b/src/newt/classes/jogamp/newt/driver/x11/X11UnderlayTracker.java index 6e64e7025..1be6dcea8 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11UnderlayTracker.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11UnderlayTracker.java @@ -38,6 +38,7 @@ import com.jogamp.common.util.ReflectionUtil; import com.jogamp.nativewindow.Capabilities; import com.jogamp.nativewindow.GraphicsConfigurationFactory; import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.util.Point; import com.jogamp.newt.Display; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Screen; @@ -135,19 +136,52 @@ public class X11UnderlayTracker implements WindowListener, KeyListener, MouseLis if (underlayWindowMap.containsKey(s)) { WindowImpl underlayWindow = (WindowImpl)s; WindowImpl overlayWindow = underlayWindowMap.get(s); - if(overlayWindow.getX()!=underlayWindow.getX() || - overlayWindow.getY()!=underlayWindow.getY()) { - overlayWindow.setPosition(underlayWindow.getX(), underlayWindow.getY()); + Point overlayOnScreen = new Point(); + Point underlayOnScreen = new Point(); + overlayWindow.getLocationOnScreen(overlayOnScreen); + underlayWindow.getLocationOnScreen(underlayOnScreen); + if(overlayOnScreen.getX()!=underlayOnScreen.getX() || + overlayOnScreen.getY()!=underlayOnScreen.getY()) { + overlayWindow.setPosition(underlayOnScreen.getX(), underlayOnScreen.getY()); } } else if (overlayWindowMap.containsKey(s)) { WindowImpl overlayWindow = (WindowImpl)s; WindowImpl underlayWindow = overlayWindowMap.get(s); - if(overlayWindow.getX()!=underlayWindow.getX() || - overlayWindow.getY()!=underlayWindow.getY()) { - //FIXME: Pressing Maximize on the underlay X11 - //with this line enabled locks-up the NEWT EDT while using the BCM.VC.IV - //underlayWindow.setPosition(overlayWindow.getX(), overlayWindow.getY()); + // FIXME: Pressing Maximize on the underlay X11 + // with these lines enabled locks-up the NEWT EDT + /* + Point overlayOnScreen = new Point(); + Point underlayOnScreen = new Point(); + overlayWindow.getLocationOnScreen(overlayOnScreen); + underlayWindow.getLocationOnScreen(underlayOnScreen); + if(overlayOnScreen.getX()!=underlayOnScreen.getX() || + overlayOnScreen.getY()!=underlayOnScreen.getY()) { + underlayWindow.setPosition(overlayOnScreen.getX(), overlayOnScreen.getY()); } + */ + /* it locks up like this + Caused by: java.lang.RuntimeException: Waited 5000ms for: <5ccc078, 45700941>[count 1, qsz 0, owner <main-Display-.x11_:0-1-EDT-1>] - <main-Display-.x11_:0-2-EDT-1> + at jogamp.common.util.locks.RecursiveLockImpl01Unfairish.lock(RecursiveLockImpl01Unfairish.java:198) + at jogamp.nativewindow.ResourceToolkitLock.lock(ResourceToolkitLock.java:56) + at com.jogamp.nativewindow.DefaultGraphicsDevice.lock(DefaultGraphicsDevice.java:126) + at jogamp.newt.DisplayImpl.runWithLockedDevice(DisplayImpl.java:780) + at jogamp.newt.DisplayImpl.runWithLockedDisplayDevice(DisplayImpl.java:793) + at jogamp.newt.driver.x11.WindowDriver.runWithLockedDisplayDevice(WindowDriver.java:425) + at jogamp.newt.driver.x11.WindowDriver.getLocationOnScreenImpl(WindowDriver.java:334) + at jogamp.newt.WindowImpl.getLocationOnScreen(WindowImpl.java:1113) + at jogamp.newt.driver.x11.X11UnderlayTracker.windowMoved(X11UnderlayTracker.java:153) + at jogamp.newt.WindowImpl.consumeWindowEvent(WindowImpl.java:4243) + at jogamp.newt.WindowImpl.sendWindowEvent(WindowImpl.java:4174) + at jogamp.newt.WindowImpl.positionChanged(WindowImpl.java:4403) + at jogamp.newt.WindowImpl.sizePosMaxInsetsChanged(WindowImpl.java:4567) + at jogamp.newt.driver.x11.DisplayDriver.DispatchMessages0(Native Method) + at jogamp.newt.driver.x11.DisplayDriver.dispatchMessagesNative(DisplayDriver.java:112) + at jogamp.newt.WindowImpl.waitForPosition(WindowImpl.java:4438) + at jogamp.newt.WindowImpl.access$2200(WindowImpl.java:96) + at jogamp.newt.WindowImpl$SetPositionAction.run(WindowImpl.java:2765) + at com.jogamp.common.util.RunnableTask.run(RunnableTask.java:150) + at jogamp.newt.DefaultEDTUtil$NEDT.run(DefaultEDTUtil.java:372) + */ } } @@ -366,20 +400,16 @@ public class X11UnderlayTracker implements WindowListener, KeyListener, MouseLis @Override public void keyPressed(KeyEvent e) { if (focusedWindow != null) { - // e.setConsumed(false); - // focusedWindow.consumeEvent(e); focusedWindow.sendKeyEvent(e.getEventType(), e.getModifiers(), - e.getKeyCode(), e.getKeyCode(), (char) e.getKeySymbol()); + e.getKeyCode(), e.getKeySymbol(), e.getKeyChar()); } } @Override public void keyReleased(KeyEvent e) { if (focusedWindow != null) { - // e.setConsumed(false); - // focusedWindow.consumeEvent(e); focusedWindow.sendKeyEvent(e.getEventType(), e.getModifiers(), - e.getKeyCode(), e.getKeyCode(), (char) e.getKeySymbol()); + e.getKeyCode(), e.getKeySymbol(), e.getKeyChar()); } } diff --git a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java index 2bdab2796..260a1beb4 100644 --- a/src/newt/classes/jogamp/newt/event/NEWTEventTask.java +++ b/src/newt/classes/jogamp/newt/event/NEWTEventTask.java @@ -38,19 +38,27 @@ public class NEWTEventTask { private final NEWTEvent event; private final Object notifyObject; private RuntimeException exception; + private volatile boolean dispatched; public NEWTEventTask(final NEWTEvent event, final Object notifyObject) { this.event = event ; this.notifyObject = notifyObject ; this.exception = null; + this.dispatched = false; } public final NEWTEvent get() { return event; } public final void setException(final RuntimeException e) { exception = e; } public final RuntimeException getException() { return exception; } public final boolean isCallerWaiting() { return null != notifyObject; } + public final boolean isDispatched() { return dispatched; } + public final void setDispatched() { dispatched = true; } + /** + * Notifies caller after {@link #setDispatched()}. + */ public void notifyCaller() { + setDispatched(); if(null != notifyObject) { synchronized (notifyObject) { notifyObject.notifyAll(); diff --git a/src/newt/classes/jogamp/newt/javafx/JFXEDTUtil.java b/src/newt/classes/jogamp/newt/javafx/JFXEDTUtil.java new file mode 100644 index 000000000..4ee15b43d --- /dev/null +++ b/src/newt/classes/jogamp/newt/javafx/JFXEDTUtil.java @@ -0,0 +1,358 @@ +/** + * Copyright 2019 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.newt.javafx; + +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.javafx.JFXAccessor; + +import jogamp.newt.Debug; + +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; +import com.jogamp.common.util.RunnableTask; +import com.jogamp.newt.util.EDTUtil; + +import javafx.application.Platform; + +/** + * Simple {@link EDTUtil} implementation utilizing the JFX UI thread + * of the given {@link Display}. + */ +public class JFXEDTUtil implements EDTUtil { + public static final boolean DEBUG = Debug.debug("EDT"); + + private final Object edtLock = new Object(); // locking the EDT start/stop state + private final ThreadGroup threadGroup; + private final String name; + private final Runnable dispatchMessages; + private NEDT nedt = null; + private int start_iter=0; + private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; + + public JFXEDTUtil(final com.jogamp.newt.Display newtDisplay) { + this.threadGroup = Thread.currentThread().getThreadGroup(); + this.name=Thread.currentThread().getName()+"-JFXDisplay-"+newtDisplay.getFQName()+"-EDT-"; + this.dispatchMessages = new Runnable() { + @Override + public void run() { + ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages(); + } }; + this.nedt = new NEDT(threadGroup, name); + this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + + @Override + public long getPollPeriod() { + return pollPeriod; + } + + @Override + public void setPollPeriod(final long ms) { + pollPeriod = ms; // writing to static field is intended + } + + @Override + public final void start() throws IllegalStateException { + synchronized(edtLock) { + if( nedt.isRunning() ) { + final Thread curT = Thread.currentThread(); + final boolean onJFXEDT = JFXAccessor.isJFXThread(); + throw new IllegalStateException("EDT still running and not subject to stop. Curr "+curT.getName()+ + ", NEDT "+nedt.getName()+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", JFX-EDT "+JFXAccessor.getJFXThreadName()+", on JFX-EDT "+onJFXEDT); + } + if(DEBUG) { + System.err.println(Thread.currentThread()+": JFX-EDT reset - edt: "+nedt); + } + if( !JFXAccessor.hasJFXThreadStopped() ) { + if( nedt.getState() != Thread.State.NEW ) { + nedt = new NEDT(threadGroup, name); + nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + startImpl(); + } + } + if( !JFXAccessor.hasJFXThreadStopped() ) { + if( !nedt.isRunning() ) { + throw new RuntimeException("EDT could not be started: "+nedt); + } + } else { + // FIXME: Throw exception ? + } + } + + private final void startImpl() { + if(nedt.isAlive()) { + throw new RuntimeException("JFX-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning+", shouldStop "+nedt.shouldStop+", edt: "+nedt); + } + start_iter++; + nedt.setName(name+start_iter); + if(DEBUG) { + System.err.println(Thread.currentThread()+": JFX-EDT START - edt: "+nedt+", jfxThread "+JFXAccessor.getJFXThreadName()); + // Thread.dumpStack(); + } + nedt.start(); + } + + @Override + public boolean isCurrentThreadEDT() { + return JFXAccessor.isJFXThread(); + } + + @Override + public final boolean isCurrentThreadNEDT() { + return nedt == Thread.currentThread(); + } + + @Override + public final boolean isCurrentThreadEDTorNEDT() { + return JFXAccessor.isJFXThread() || Thread.currentThread() == nedt ; + } + + @Override + public boolean isRunning() { + return nedt.isRunning(); + } + + @Override + public final boolean invokeStop(final boolean wait, final Runnable task) { + return invokeImpl(wait, task, true); + } + + @Override + public final boolean invoke(final boolean wait, final Runnable task) { + return invokeImpl(wait, task, false); + } + + private static Runnable nullTask = new Runnable() { + @Override + public void run() { } + }; + + private final boolean invokeImpl(boolean wait, final Runnable task, boolean stop) { + final RunnableTask rTask; + final Object rTaskLock = new Object(); + synchronized(rTaskLock) { // lock the optional task execution + synchronized(edtLock) { // lock the EDT status + if( nedt.shouldStop ) { + // drop task .. + if(DEBUG) { + System.err.println(Thread.currentThread()+": Warning: JFX-EDT about (1) to stop, won't enqueue new task: "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop); + ExceptionUtils.dumpStack(System.err); + } + return false; + } + final boolean hasJFXThreadStopped = JFXAccessor.hasJFXThreadStopped(); + + if( hasJFXThreadStopped ) { + stop = true; + } + + if( isCurrentThreadEDT() ) { + if(null != task) { + task.run(); + } + wait = false; // running in same thread (EDT) -> no wait + rTask = null; + if( stop ) { + nedt.shouldStop = true; + } + } else { + if( !nedt.isRunning && !hasJFXThreadStopped ) { + if( null != task ) { + if( stop ) { + System.err.println(Thread.currentThread()+": Warning: JFX-EDT is about (3) to stop and stopped already, dropping task. NEDT "+nedt); + } else { + System.err.println(Thread.currentThread()+": Warning: JFX-EDT is not running, dropping task. NEDT "+nedt); + } + if(DEBUG) { + ExceptionUtils.dumpStack(System.err); + } + } + return false; + } else if( stop ) { + if( nedt.isRunning ) { + if(DEBUG) { + System.err.println(Thread.currentThread()+": JFX-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop); + } + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } + } + if( JFXAccessor.hasJFXThreadStopped() ) { + System.err.println(Thread.currentThread()+": Warning: JFX-EDT is about (3) to stop and stopped already, dropping task. "+nedt); + if(DEBUG) { + ExceptionUtils.dumpStack(System.err); + } + return false; + } + } + + if( null != task ) { + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */, + wait ? null : System.err); + Platform.runLater(rTask); + } else { + wait = false; + rTask = null; + } + } + } + if( wait ) { + try { + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rTask.getThrowable(); + if(null!=throwable) { + if(throwable instanceof NativeWindowException) { + throw (NativeWindowException)throwable; + } + throw new RuntimeException(throwable); + } + } + return true; + } + } + + @Override + final public boolean waitUntilIdle() { + final NEDT _nedt; + synchronized(edtLock) { + _nedt = nedt; + } + if( !_nedt.isRunning || Thread.currentThread() == _nedt || JFXAccessor.hasJFXThreadStopped() || JFXAccessor.isJFXThread() ) { + return false; + } + JFXAccessor.runOnJFXThread(true, nullTask); + return true; + } + + @Override + final public boolean waitUntilStopped() { + synchronized(edtLock) { + final Thread curT = Thread.currentThread(); + final boolean onJFXEDT = JFXAccessor.isJFXThread(); + if( nedt.isRunning && nedt != curT && !onJFXEDT ) { + try { + while( nedt.isRunning ) { + edtLock.wait(); + } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); + } + return true; + } else { + return false; + } + } + } + + class NEDT extends InterruptSource.Thread { + volatile boolean shouldStop = false; + volatile boolean isRunning = false; + Object sync = new Object(); + + public NEDT(final ThreadGroup tg, final String name) { + super(tg, null, name); + } + + final public boolean isRunning() { + return isRunning && !shouldStop; + } + + @Override + final public void start() throws IllegalThreadStateException { + isRunning = true; + super.start(); + } + + /** + * Utilizing locking only on tasks and its execution, + * not for event dispatching. + */ + @Override + final public void run() { + if(DEBUG) { + System.err.println(getName()+": JFX-EDT run() START "+ getName()); + } + RuntimeException error = null; + try { + do { + // event dispatch + if(!shouldStop) { + // EDT invoke thread is JFX-EDT, + // hence dispatching is required to run on JFX-EDT as well. + // Otherwise a deadlock may happen due to dispatched event's + // triggering a locking action. + JFXAccessor.runOnJFXThread(true, dispatchMessages); + } + // wait + synchronized(sync) { + if(!shouldStop) { + try { + sync.wait(pollPeriod); + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); + } + } + } + } while(!shouldStop) ; + } catch (final Throwable t) { + // handle errors .. + shouldStop = true; + if(t instanceof RuntimeException) { + error = (RuntimeException) t; + } else { + error = new RuntimeException("Within JFX-EDT", t); + } + } finally { + if(DEBUG) { + System.err.println(getName()+": JFX-EDT run() END "+ getName()+", "+error); + } + synchronized(edtLock) { + isRunning = false; + edtLock.notifyAll(); + } + if(DEBUG) { + System.err.println(getName()+": JFX-EDT run() EXIT "+ getName()+", exception: "+error); + } + if(null!=error) { + throw error; + } + } // finally + } // run() + } // EventDispatchThread + +} diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java index 9039b6083..9d2b41bbc 100644 --- a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java @@ -32,6 +32,8 @@ import com.jogamp.nativewindow.NativeWindowException; import jogamp.newt.Debug; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.common.util.RunnableTask; import com.jogamp.newt.util.EDTUtil; @@ -162,8 +164,7 @@ public class SWTEDTUtil implements EDTUtil { } private final boolean invokeImpl(boolean wait, final Runnable task, boolean stop) { - Throwable throwable = null; - RunnableTask rTask = null; + final RunnableTask rTask; final Object rTaskLock = new Object(); synchronized(rTaskLock) { // lock the optional task execution synchronized(edtLock) { // lock the EDT status @@ -184,6 +185,7 @@ public class SWTEDTUtil implements EDTUtil { task.run(); } wait = false; // running in same thread (EDT) -> no wait + rTask = null; if( stop ) { nedt.shouldStop = true; } @@ -225,18 +227,21 @@ public class SWTEDTUtil implements EDTUtil { true /* always catch and report Exceptions, don't disturb EDT */, wait ? null : System.err); swtDisplay.asyncExec(rTask); + } else { + wait = false; + rTask = null; } } } if( wait ) { try { - rTaskLock.wait(); // free lock, allow execution of rTask + while( rTask.isInQueue() ) { + rTaskLock.wait(); // free lock, allow execution of rTask + } } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); + throw new InterruptedRuntimeException(ie); } + final Throwable throwable = rTask.getThrowable(); if(null!=throwable) { if(throwable instanceof NativeWindowException) { throw (NativeWindowException)throwable; @@ -274,12 +279,12 @@ public class SWTEDTUtil implements EDTUtil { final Thread swtT = !swtDisplay.isDisposed() ? swtDisplay.getThread() : null; final boolean onSWTEDT = swtT == curT; if( nedt.isRunning && nedt != curT && !onSWTEDT ) { - while( nedt.isRunning ) { - try { + try { + while( nedt.isRunning ) { edtLock.wait(); - } catch (final InterruptedException e) { - e.printStackTrace(); } + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); } return true; } else { @@ -288,13 +293,13 @@ public class SWTEDTUtil implements EDTUtil { } } - class NEDT extends Thread { + class NEDT extends InterruptSource.Thread { volatile boolean shouldStop = false; volatile boolean isRunning = false; Object sync = new Object(); public NEDT(final ThreadGroup tg, final String name) { - super(tg, name); + super(tg, null, name); } final public boolean isRunning() { @@ -337,7 +342,7 @@ public class SWTEDTUtil implements EDTUtil { try { sync.wait(pollPeriod); } catch (final InterruptedException e) { - e.printStackTrace(); + throw new InterruptedRuntimeException(e); } } } diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index b59e19e4e..ee012add3 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -832,8 +832,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow } JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getDisplayID0(JNIEnv *env, jobject jthis, jlong window) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* myWindow = (NewtMacWindow*) ((intptr_t) window); + if( NULL == myWindow ) { + DBG_PRINT( "getDisplayID0 - NULL NEWT win - abort\n"); + return 0; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSScreen *screen = [myWindow screen]; int32_t displayID = (int32_t)NewtScreen_getCGDirectDisplayIDByNSScreen(screen); [pool release]; @@ -849,16 +853,16 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getDisplayID0 */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initWindow0 (JNIEnv *env, jobject jthis, jlong parent, jlong window, jint x, jint y, jint w, jint h, jfloat reqPixelScale, - jboolean opaque, jboolean visible, jlong jview) + jboolean opaque, jboolean atop, jboolean abottom, jboolean visible, jlong jview) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* myWindow = (NewtMacWindow*) ((intptr_t) window); NewtView* myView = (NewtView*) (intptr_t) jview ; BOOL fullscreen = myWindow->isFullscreenWindow; - DBG_PRINT( "initWindow0 - %p (this), %p (parent), %p (window), %d/%d %dx%d, reqPixScale %f, opaque %d, fs %d, visible %d, view %p (START)\n", + DBG_PRINT( "initWindow0 - %p (this), %p (parent), %p (window), %d/%d %dx%d, reqPixScale %f, opaque %d, atop %d, abottom %d, fs %d, visible %d, view %p (START)\n", (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, (int)x, (int)y, (int)w, (int)h, (float)reqPixelScale, - (int) opaque, (int)fullscreen, (int)visible, myView); + (int) opaque, (int)atop, (int)abottom, (int)fullscreen, (int)visible, myView); NS_DURING // HiDPI scaling: Setup - Available >= 10.7 @@ -921,6 +925,7 @@ NS_ENDHANDLER [myWindow setOpaque: NO]; [myWindow setBackgroundColor: [NSColor clearColor]]; } + [myWindow setAlwaysOn: atop bottom:abottom]; // specify we want mouse-moved events [myWindow setAcceptsMouseMovedEvents:YES]; @@ -1035,8 +1040,12 @@ NS_ENDHANDLER JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPixelScale0 (JNIEnv *env, jobject jthis, jlong window, jlong view, jfloat reqPixelScale) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* myWindow = (NewtMacWindow*) ((intptr_t) window); + if( NULL == myWindow ) { + DBG_PRINT( "setPixelScale0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* myView = (NewtView*) (intptr_t) view ; #ifdef VERBOSE_ON int dbgIdx = 1; @@ -1195,8 +1204,12 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_unlockSur JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_requestFocus0 (JNIEnv *env, jobject window, jlong w, jboolean force) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* mWin = (NSWindow*) ((intptr_t) w); + if( NULL == mWin ) { + DBG_PRINT( "requestFocus - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; #ifdef VERBOSE_ON BOOL hasFocus = [mWin isKeyWindow]; #endif @@ -1220,12 +1233,16 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_requestFocus0 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_resignFocus0 (JNIEnv *env, jobject window, jlong w) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* mWin = (NSWindow*) ((intptr_t) w); + if( NULL == mWin ) { + DBG_PRINT( "resignFocus0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* pWin = [mWin parentWindow]; BOOL hasFocus = [mWin isKeyWindow]; - DBG_PRINT( "requestFocusParent0 - window: %p, parent %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); + DBG_PRINT( "resignFocus0 - window: %p, parent %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); if( hasFocus ) { if(NULL != pWin) { // [mWin makeFirstResponder: pWin]; @@ -1234,7 +1251,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_resignFocus0 [pWin resignKeyWindow]; } } - DBG_PRINT( "requestFocusParent0 - window: %p (END)\n", mWin); + DBG_PRINT( "resignFocus0 - window: %p (END)\n", mWin); [pool release]; } @@ -1247,8 +1264,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_resignFocus0 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderFront0 (JNIEnv *env, jobject unused, jlong window) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* mWin = (NSWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "orderFront0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* pWin = [mWin parentWindow]; DBG_PRINT( "orderFront0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]); @@ -1272,8 +1293,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderFront0 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderOut0 (JNIEnv *env, jobject unused, jlong window) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* mWin = (NSWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "orderOut0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* pWin = [mWin parentWindow]; DBG_PRINT( "orderOut0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]); @@ -1297,8 +1322,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderOut0 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setTitle0 (JNIEnv *env, jobject unused, jlong window, jstring title) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); + if( NULL == win ) { + DBG_PRINT( "setTitle0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; DBG_PRINT( "setTitle0 - window: %p (START)\n", win); @@ -1374,88 +1403,64 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_changeContent /* * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: setWindowClientTopLeftPointAndSize0 - * Signature: (JIIIIZ)V + * Method: updateSizePosInsets0 + * Signature: (JZ)V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPointAndSize0 - (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jint w, jint h, jboolean display) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_updateSizePosInsets0 + (JNIEnv *env, jobject jthis, jlong window, jboolean defer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); - DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (START)\n", mWin); + DBG_PRINT( "updateSizePosInsets - window: %p, defer %d (START)\n", mWin, (int)defer); - setWindowClientTopLeftPointAndSize(mWin, x, y, w, h, display); + [mWin updateSizePosInsets: env jwin:jthis defer:defer]; - DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (END)\n", mWin); + DBG_PRINT( "updateSizePosInsets - window: %p, defer %d (END)\n", mWin, (int)defer); [pool release]; } /* * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: setWindowClientTopLeftPoint0 - * Signature: (JIIZ)V + * Method: setWindowClientTopLeftPointAndSize0 + * Signature: (JIIIIZ)V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPoint0 - (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jboolean display) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPointAndSize0 + (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jint w, jint h, jboolean display) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); - DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (START)\n", mWin); + DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (START)\n", mWin); - setWindowClientTopLeftPoint(mWin, x, y, display); + setWindowClientTopLeftPointAndSize(mWin, x, y, w, h, display); - DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (END)\n", mWin); + DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (END)\n", mWin); [pool release]; } /* * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: setAlwaysOnTop0 - * Signature: (JZ)V + * Method: setWindowClientTopLeftPoint0 + * Signature: (JIIZ)V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setAlwaysOnTop0 - (JNIEnv *env, jobject unused, jlong window, jboolean atop) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPoint0 + (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jboolean display) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) window); - - DBG_PRINT( "setAlwaysOnTop0 - window: %p, atop %d (START)\n", win, (int)atop); - - if(atop) { - [win setLevel:NSFloatingWindowLevel]; - } else { - [win setLevel:NSNormalWindowLevel]; + NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "setWindowClientTopLeftPoint - NULL NEWT win - abort\n"); + return; } - - DBG_PRINT( "setAlwaysOnTop0 - window: %p, atop %d (END)\n", win, (int)atop); - - [pool release]; -} - -/* - * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: setAlwaysOnBottom0 - * Signature: (JZ)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setAlwaysOnBottom0 - (JNIEnv *env, jobject unused, jlong window, jboolean abottom) -{ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) window); - DBG_PRINT( "setAlwaysOnBottom0 - window: %p, abottom %d (START)\n", win, (int)abottom); + DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (START)\n", mWin); - if(abottom) { - [win setLevel:NSScreenSaverWindowLevel]; // ?? - } else { - [win setLevel:NSNormalWindowLevel]; - } + setWindowClientTopLeftPoint(mWin, x, y, display); - DBG_PRINT( "setAlwaysOnBottom0 - window: %p, abottom %d (END)\n", win, (int)abottom); + DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (END)\n", mWin); [pool release]; } @@ -1469,6 +1474,10 @@ JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getLocatio (JNIEnv *env, jclass unused, jlong win, jint src_x, jint src_y) { NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) win; + if( NULL == mWin ) { + DBG_PRINT( "getLocationOnScreen0 - NULL NEWT win - abort\n"); + return NULL; + } if( ![mWin isKindOfClass:[NewtMacWindow class]] ) { NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); return NULL; @@ -1480,12 +1489,16 @@ JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getLocatio JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerIcon0 (JNIEnv *env, jobject unused, jlong window, jlong handle) { + NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window; + if( NULL == mWin ) { + DBG_PRINT( "setPointerIcon0 - NULL NEWT win - abort\n"); + return; + } NSCursor *c = (NSCursor*) (intptr_t) handle ; if ( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) { NewtCommon_throwNewRuntimeException(env, "Not a NSCursor %p", c); return; } - NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window; if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); return; @@ -1509,6 +1522,10 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerVis (JNIEnv *env, jclass clazz, jlong window, jboolean hasFocus, jboolean mouseVisible) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "setPointerVisible0 - NULL NEWT win - abort\n"); + return; + } if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); return; @@ -1533,6 +1550,10 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_confinePointe (JNIEnv *env, jclass clazz, jlong window, jboolean confine) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "confinePointer0 - NULL NEWT win - abort\n"); + return; + } if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); return; @@ -1556,6 +1577,10 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_warpPointer0 (JNIEnv *env, jclass clazz, jlong window, jint x, jint y) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "warpPointer0 - NULL NEWT win - abort\n"); + return; + } if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); return; diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index 7dc5c6e19..14474bc10 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -142,6 +142,7 @@ CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen); #endif { BOOL realized; + jboolean withinLiveResize; @public BOOL hasPresentationSwitch; NSUInteger defaultPresentationOptions; @@ -164,7 +165,10 @@ CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen); - (void) setRealized: (BOOL)v; - (BOOL) isRealized; +- (void) setAlwaysOn: (BOOL)top bottom:(BOOL)bottom; + - (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin; +- (void) updateSizePosInsets: (JNIEnv*) env jwin: (jobject) javaWin defer: (jboolean)defer; - (void) attachToParent: (NSWindow*) parent; - (void) detachFromParent: (NSWindow*) parent; @@ -189,7 +193,12 @@ CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen); - (void) windowDidBecomeKey: (NSNotification *) notification; - (void) windowDidResignKey: (NSNotification *) notification; +- (void) windowWillStartLiveResize: (NSNotification *) notification; +- (void) windowDidEndLiveResize: (NSNotification *) notification; +- (NSSize) windowWillResize: (NSWindow *)sender toSize:(NSSize)frameSize; - (void) windowDidResize: (NSNotification*) notification; +- (void) sendResizeEvent; + - (void) windowDidMove: (NSNotification*) notification; - (BOOL) windowClosingImpl: (BOOL) force; - (BOOL) windowShouldClose: (id) sender; diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 7b3df391d..6024a90d4 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -54,7 +54,7 @@ static jfloat GetDelta(NSEvent *event, jint javaMods[]) { deltaX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2); deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); // fprintf(stderr, "WHEEL/PAD: %lf/%lf - 0x%X\n", (double)deltaX, (double)deltaY, javaMods[0]); - if( fabsf(deltaX) > fabsf(deltaY) ) { + if( fabs(deltaX) > fabs(deltaY) ) { javaMods[0] |= EVENT_SHIFT_MASK; delta = deltaX; } else { @@ -179,9 +179,10 @@ static jmethodID requestFocusID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; +static jmethodID sizeScreenPosInsetsChangedID = NULL; static jmethodID updatePixelScaleID = NULL; static jmethodID visibleChangedID = NULL; -static jmethodID positionChangedID = NULL; +static jmethodID screenPositionChangedID = NULL; static jmethodID focusChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowRepaintID = NULL; @@ -649,31 +650,32 @@ static jmethodID windowRepaintID = NULL; // convert to 1-based button number (or use zero if no button is involved) // TODO: detect mouse button when mouse wheel scrolled - jshort javaButtonNum = 0; + jshort javaButtonNum; jfloat scrollDeltaY = 0.0f; switch ([event type]) { - case NSScrollWheel: { - scrollDeltaY = GetDelta(event, javaMods); - javaButtonNum = 1; - break; - } - case NSLeftMouseDown: - case NSLeftMouseUp: - case NSLeftMouseDragged: - javaButtonNum = 1; - break; - case NSRightMouseDown: - case NSRightMouseUp: - case NSRightMouseDragged: - javaButtonNum = 3; - break; - case NSOtherMouseDown: - case NSOtherMouseUp: - case NSOtherMouseDragged: - javaButtonNum = 2; - break; + case NSScrollWheel: + scrollDeltaY = GetDelta(event, javaMods); + javaButtonNum = 1; + break; + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSLeftMouseDragged: + javaButtonNum = 1; + break; + case NSRightMouseDown: + case NSRightMouseUp: + case NSRightMouseDragged: + javaButtonNum = 3; + break; + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSOtherMouseDragged: + javaButtonNum = 2; + break; + default: + javaButtonNum = 0; + break; } - if (evType == EVENT_MOUSE_WHEEL_MOVED && scrollDeltaY == 0) { // ignore 0 increment wheel scroll events return; @@ -830,13 +832,15 @@ NS_ENDHANDLER updatePixelScaleID = (*env)->GetMethodID(env, clazz, "updatePixelScale", "(ZFF)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); - positionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V"); + sizeScreenPosInsetsChangedID = (*env)->GetMethodID(env, clazz, "sizeScreenPosInsetsChanged", "(ZIIIIIIIIZZ)V"); + screenPositionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V"); focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); - if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && updatePixelScaleID && visibleChangedID && insetsChangedID && - positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) + if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && updatePixelScaleID && visibleChangedID && + insetsChangedID && sizeScreenPosInsetsChangedID && + screenPositionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) { CKCH_CreateDictionaries(); return YES; @@ -889,6 +893,7 @@ NS_ENDHANDLER cachedInsets[3] = 0; // b realized = YES; + withinLiveResize = JNI_FALSE; DBG_PRINT("NewtWindow::create: %p, realized %d, hasPresentationSwitch %d[defaultOptions 0x%X, fullscreenOptions 0x%X], (refcnt %d)\n", res, realized, (int)hasPresentationSwitch, (int)defaultPresentationOptions, (int)fullscreenPresentationOptions, (int)[res retainCount]); return res; @@ -928,6 +933,20 @@ NS_ENDHANDLER return realized; } +- (void) setAlwaysOn: (BOOL)top bottom:(BOOL)bottom +{ + if( top ) { + DBG_PRINT( "*************** setAlwaysOn -> top\n"); + [self setLevel: kCGMaximumWindowLevel]; + } else if ( bottom ) { + DBG_PRINT( "*************** setAlwaysOn -> bottom\n"); + [self setLevel: kCGDesktopIconWindowLevel]; // w/ input + } else { + DBG_PRINT( "*************** setAlwaysOn -> normal\n"); + [self setLevel:NSNormalWindowLevel]; + } +} + - (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin { NSRect frameRect = [self frame]; @@ -948,6 +967,33 @@ NS_ENDHANDLER } } +- (void) updateSizePosInsets: (JNIEnv*) env jwin: (jobject) javaWin defer: (jboolean)defer +{ + // update insets on every window resize for lack of better hook place + [self updateInsets: NULL jwin:NULL]; + + NSRect frameRect = [self frame]; + NSRect contentRect = [self contentRectForFrameRect: frameRect]; + + DBG_PRINT( "updateSize: [ w %d, h %d ], liveResize %d\n", (jint) contentRect.size.width, (jint) contentRect.size.height, (jint)withinLiveResize); + + NSPoint p0 = { 0, 0 }; + p0 = [self getLocationOnScreen: p0]; + + DBG_PRINT( "updatePos: [ x %d, y %d ]\n", (jint) p0.x, (jint) p0.y); + + if( NULL != env && NULL != javaWin ) { + (*env)->CallVoidMethod(env, javaWin, sizeScreenPosInsetsChangedID, defer, + (jint) p0.x, (jint) p0.y, + (jint) contentRect.size.width, (jint) contentRect.size.height, + cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3], + JNI_FALSE, // force + withinLiveResize + ); + } +} + + - (void) attachToParent: (NSWindow*) parent { DBG_PRINT( "attachToParent.1\n"); @@ -1183,8 +1229,30 @@ NS_ENDHANDLER [self focusChanged: NO]; } +- (void) windowWillStartLiveResize: (NSNotification *) notification +{ + DBG_PRINT( "*************** windowWillStartLiveResize\n"); + withinLiveResize = JNI_TRUE; +} +- (void) windowDidEndLiveResize: (NSNotification *) notification +{ + DBG_PRINT( "*************** windowDidEndLiveResize\n"); + withinLiveResize = JNI_FALSE; + [self sendResizeEvent]; +} +- (NSSize) windowWillResize: (NSWindow *)sender toSize:(NSSize)frameSize +{ + DBG_PRINT( "*************** windowWillResize %lfx%lf\n", frameSize.width, frameSize.height); + return frameSize; +} - (void)windowDidResize: (NSNotification*) notification { + DBG_PRINT( "*************** windowDidResize\n"); + [self sendResizeEvent]; +} + +- (void) sendResizeEvent +{ jobject javaWindowObject = NULL; int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); @@ -1198,15 +1266,7 @@ NS_ENDHANDLER javaWindowObject = [newtView getJavaWindowObject]; } if( NULL != javaWindowObject ) { - // update insets on every window resize for lack of better hook place - [self updateInsets: env jwin:javaWindowObject]; - - NSRect frameRect = [self frame]; - NSRect contentRect = [self contentRectForFrameRect: frameRect]; - - (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_TRUE, // defer - (jint) contentRect.size.width, - (jint) contentRect.size.height, JNI_FALSE); + [self updateSizePosInsets: env jwin: javaWindowObject defer:JNI_TRUE]; } // detaching thread not required - daemon // NewtCommon_ReleaseJNIEnv(shallBeDetached); @@ -1232,7 +1292,8 @@ NS_ENDHANDLER NSPoint p0 = { 0, 0 }; p0 = [self getLocationOnScreen: p0]; - (*env)->CallVoidMethod(env, javaWindowObject, positionChangedID, JNI_FALSE, (jint) p0.x, (jint) p0.y); + DBG_PRINT( "windowDidMove: [ x %d, y %d ]\n", (jint) p0.x, (jint) p0.y); + (*env)->CallVoidMethod(env, javaWindowObject, screenPositionChangedID, JNI_TRUE, (jint) p0.x, (jint) p0.y); // detaching thread not required - daemon // NewtCommon_ReleaseJNIEnv(shallBeDetached); diff --git a/src/newt/native/Window.h b/src/newt/native/Window.h index ada886d24..f6aba4c83 100644 --- a/src/newt/native/Window.h +++ b/src/newt/native/Window.h @@ -53,7 +53,9 @@ #define FLAG_IS_MAXIMIZED_VERT ( 1 << 9 ) #define FLAG_IS_MAXIMIZED_HORZ ( 1 << 10 ) #define FLAG_IS_FULLSCREEN ( 1 << 11 ) -#define FLAG_IS_FULLSCREEN_SPAN ( 1 << 12 ) +#define FLAG_IS_POINTERVISIBLE ( 1 << 12 ) +#define FLAG_IS_POINTERCONFINED ( 1 << 13 ) +#define FLAG_IS_FULLSCREEN_SPAN ( 1 << 14 ) #define TST_FLAG_CHANGE_VISIBILITY(f) ( 0 != ( (f) & FLAG_CHANGE_VISIBILITY ) ) #define TST_FLAG_CHANGE_VISIBILITY_FAST(f) ( 0 != ( (f) & FLAG_CHANGE_VISIBILITY_FAST ) ) diff --git a/src/newt/native/WindowsEDID.c b/src/newt/native/WindowsEDID.c index d84773dc6..5fc410a91 100644 --- a/src/newt/native/WindowsEDID.c +++ b/src/newt/native/WindowsEDID.c @@ -144,8 +144,14 @@ static _TCHAR* Get2ndSlashBlock(const _TCHAR* sIn, _TCHAR* sOut, size_t sOutLen) size_t len = t - s; if( len > 0 ) { if( sOutLen >= len ) { - _tcsncpy_s(sOut, sOutLen, s, len); - return sOut; + // Bug 1196: Unresolved strncpy_s (MSVCRT) on WinXP. + // Mapped: _tcsncpy_s -> strncpy_s (!UNICODE). + // On WinXP MSVCRT has no strncpy_s. + // _tcsncpy_s(sOut, sOutLen, s, len); + if( len <= sOutLen-1 ) { + _tcsncpy(sOut, s, len); + return sOut; + } } } } diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index ad4111ec7..59e054516 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -177,9 +177,11 @@ static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; +static jmethodID maximizedChangedID = NULL; static jmethodID positionChangedID = NULL; static jmethodID focusChangedID = NULL; static jmethodID visibleChangedID = NULL; +static jmethodID sizePosInsetsFocusVisibleChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowRepaintID = NULL; static jmethodID sendMouseEventID = NULL; @@ -202,15 +204,23 @@ static UnregisterTouchWindowPROCADDR WinTouch_UnregisterTouchWindow = NULL; static int NewtEDID_avail = 0; -static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd); - typedef struct { JNIEnv* jenv; jobject jinstance; + /* client x-pos */ + int xpos; + /* client y-pos */ + int ypos; /* client size width */ int width; /* client size height */ int height; + /* visible state */ + BOOL visible; + /* focused state */ + BOOL focused; + /* Insets left, right, top, bottom */ + RECT insets; /** Tristate: -1 HIDE, 0 NOP, 1 SHOW */ int setPointerVisible; /** Tristate: -1 RESET, 0 NOP, 1 SET-NEW */ @@ -218,9 +228,17 @@ typedef struct { HCURSOR setPointerHandle; HCURSOR defPointerHandle; /** Bool: 0 NOP, 1 FULLSCREEN */ - int isFullscreen; + BOOL isFullscreen; /** Bool: 0 TOP, 1 CHILD */ - int isChildWindow; + BOOL isChildWindow; + /** Bool: 0 NOP, 1 minimized/iconic */ + BOOL isMinimized; + /** Bool: 0 NOP, 1 maximized */ + BOOL isMaximized; + BOOL isOnBottom; + BOOL isOnTop; + /** Bug 1205: Clear Window Background -> security! */ + BOOL isInCreation; int pointerCaptured; int pointerInside; int touchDownCount; @@ -228,6 +246,8 @@ typedef struct { int supportsMTouch; } WindowUserData; +static void UpdateInsets(JNIEnv *env, WindowUserData *wud, HWND hwnd); + typedef struct { USHORT javaKey; USHORT windowsKey; @@ -601,21 +621,41 @@ static int WmKeyUp(JNIEnv *env, jobject window, USHORT wkey, WORD repCnt, BYTE s static void NewtWindows_requestFocus (JNIEnv *env, jobject window, HWND hwnd, jboolean force) { HWND pHwnd, current; + WindowUserData * wud; BOOL isEnabled = IsWindowEnabled(hwnd); pHwnd = GetParent(hwnd); current = GetFocus(); - DBG_PRINT("*** WindowsWindow: requestFocus.S force %d, parent %p, window %p, isEnabled %d, isCurrent %d\n", - (int)force, (void*)pHwnd, (void*)hwnd, isEnabled, current==hwnd); +#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) + wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA); +#else + wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#endif + + DBG_PRINT("*** WindowsWindow: requestFocus.S force %d, parent %p, window %p, isEnabled %d, isCurrent %d, isOn[Top %d, Bottom %d]\n", + (int)force, (void*)pHwnd, (void*)hwnd, isEnabled, current==hwnd, + wud->isOnTop, wud->isOnBottom); if( JNI_TRUE==force || current!=hwnd || !isEnabled ) { UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; if(!isEnabled) { EnableWindow(hwnd, TRUE); } - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); - SetForegroundWindow(hwnd); // Slightly Higher Priority + BOOL frontWindow; + if( wud->isOnBottom ) { + SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + frontWindow = FALSE; + } else if( wud->isOnTop ) { + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, flags); + frontWindow = TRUE; + } else { + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); + frontWindow = TRUE; + } + if( frontWindow ) { + SetForegroundWindow(hwnd); // Slightly Higher Priority + } SetFocus(hwnd);// Sets Keyboard Focus To Window (activates parent window if exist, or this window) - if(NULL!=pHwnd) { + if( frontWindow && NULL!=pHwnd ) { SetActiveWindow(hwnd); } current = GetFocus(); @@ -660,91 +700,34 @@ static jboolean NewtWindows_setFullScreen(jboolean fullscreen) return ( DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettings(&dm, flags) ) ? JNI_TRUE : JNI_FALSE; } -#if 0 - -static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd) -{ - // being naughty here - static RECT m_insets = { 0, 0, 0, 0 }; - RECT outside; - RECT inside; - POINT *rp_inside = (POINT *) (void *) &inside; - int dx, dy, dw, dh; - - if (IsIconic(hwnd)) { - m_insets.left = m_insets.top = m_insets.right = m_insets.bottom = -1; - return FALSE; - } - - m_insets.left = m_insets.top = m_insets.right = m_insets.bottom = 0; - - GetClientRect(hwnd, &inside); - GetWindowRect(hwnd, &outside); - - DBG_PRINT("*** WindowsWindow: UpdateInsets (a1) window %p, Inside CC: %d/%d - %d/%d %dx%d\n", - (void*)hwnd, - (int)inside.left, (int)inside.top, (int)inside.right, (int)inside.bottom, - (int)(inside.right - inside.left), (int)(inside.bottom - inside.top)); - DBG_PRINT("*** WindowsWindow: UpdateInsets (a1) window %p, Outside SC: %d/%d - %d/%d %dx%d\n", - (void*)hwnd, - (int)outside.left, (int)outside.top, (int)outside.right, (int)outside.bottom, - (int)(outside.right - outside.left), (int)(outside.bottom - outside.top)); - - // xform client -> screen coord - ClientToScreen(hwnd, rp_inside); - ClientToScreen(hwnd, rp_inside+1); - - DBG_PRINT("*** WindowsWindow: UpdateInsets (a2) window %p, Inside SC: %d/%d - %d/%d %dx%d\n", - (void*)hwnd, - (int)inside.left, (int)inside.top, (int)inside.right, (int)inside.bottom, - (int)(inside.right - inside.left), (int)(inside.bottom - inside.top)); - - m_insets.top = inside.top - outside.top; - m_insets.bottom = outside.bottom - inside.bottom; - m_insets.left = inside.left - outside.left; - m_insets.right = outside.right - inside.right; - - DBG_PRINT("*** WindowsWindow: UpdateInsets (1.0) window %p, %d/%d - %d/%d %dx%d\n", - (void*)hwnd, - (int)m_insets.left, (int)m_insets.top, (int)m_insets.right, (int)m_insets.bottom, - (int)(m_insets.right-m_insets.left), (int)(m_insets.top-m_insets.bottom)); - - (*env)->CallVoidMethod(env, window, insetsChangedID, JNI_FALSE, - m_insets.left, m_insets.right, - m_insets.top, m_insets.bottom); - return &m_insets; -} - -#else - -static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd) -{ - // being naughty here - static RECT m_insets = { 0, 0, 0, 0 }; +static void UpdateInsets(JNIEnv *env, WindowUserData *wud, HWND hwnd) { + jobject window = wud->jinstance; RECT outside; RECT inside; + int strategy = 0; if (IsIconic(hwnd)) { - m_insets.left = m_insets.top = m_insets.right = m_insets.bottom = -1; - return FALSE; + wud->insets.left = wud->insets.top = wud->insets.right = wud->insets.bottom = -1; + return; } - m_insets.left = m_insets.top = m_insets.right = m_insets.bottom = 0; + wud->insets.left = wud->insets.top = wud->insets.right = wud->insets.bottom = 0; GetClientRect(hwnd, &inside); GetWindowRect(hwnd, &outside); if (outside.right - outside.left > 0 && outside.bottom - outside.top > 0) { MapWindowPoints(hwnd, 0, (LPPOINT)&inside, 2); - m_insets.top = inside.top - outside.top; - m_insets.bottom = outside.bottom - inside.bottom; - m_insets.left = inside.left - outside.left; - m_insets.right = outside.right - inside.right; + wud->insets.top = inside.top - outside.top; + wud->insets.bottom = outside.bottom - inside.bottom; + wud->insets.left = inside.left - outside.left; + wud->insets.right = outside.right - inside.right; + strategy = 1; } else { - m_insets.top = -1; + wud->insets.top = -1; } - if (m_insets.left < 0 || m_insets.top < 0 || - m_insets.right < 0 || m_insets.bottom < 0) + if (wud->insets.left < 0 || wud->insets.top < 0 || + wud->insets.right < 0 || wud->insets.bottom < 0) { LONG style = GetWindowLong(hwnd, GWL_STYLE); @@ -752,49 +735,65 @@ static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd) if (!bIsUndecorated) { /* Get outer frame sizes. */ if (style & WS_THICKFRAME) { - m_insets.left = m_insets.right = + wud->insets.left = wud->insets.right = GetSystemMetrics(SM_CXSIZEFRAME); - m_insets.top = m_insets.bottom = + wud->insets.top = wud->insets.bottom = GetSystemMetrics(SM_CYSIZEFRAME); } else { - m_insets.left = m_insets.right = + wud->insets.left = wud->insets.right = GetSystemMetrics(SM_CXDLGFRAME); - m_insets.top = m_insets.bottom = + wud->insets.top = wud->insets.bottom = GetSystemMetrics(SM_CYDLGFRAME); } /* Add in title. */ - m_insets.top += GetSystemMetrics(SM_CYCAPTION); + wud->insets.top += GetSystemMetrics(SM_CYCAPTION); + strategy += 10; } else { /* undo the -1 set above */ - m_insets.left = m_insets.top = m_insets.right = m_insets.bottom = 0; + wud->insets.left = wud->insets.top = wud->insets.right = wud->insets.bottom = 0; + strategy += 20; } } - DBG_PRINT("*** WindowsWindow: UpdateInsets window %p, [l %d, r %d - t %d, b %d - %dx%d]\n", - (void*)hwnd, (int)m_insets.left, (int)m_insets.right, (int)m_insets.top, (int)m_insets.bottom, - (int) ( m_insets.left + m_insets.right ), (int) (m_insets.top + m_insets.bottom)); - - (*env)->CallVoidMethod(env, window, insetsChangedID, JNI_FALSE, - (int)m_insets.left, (int)m_insets.right, (int)m_insets.top, (int)m_insets.bottom); - return &m_insets; + DBG_PRINT("*** WindowsWindow: UpdateInsets window %p, s %d, [l %d, r %d - t %d, b %d - %dx%d], at-init %d\n", + (void*)hwnd, strategy, (int)wud->insets.left, (int)wud->insets.right, (int)wud->insets.top, (int)wud->insets.bottom, + (int) ( wud->insets.left + wud->insets.right ), (int) (wud->insets.top + wud->insets.bottom), wud->isInCreation); + if( !wud->isInCreation ) { + (*env)->CallVoidMethod(env, window, insetsChangedID, JNI_FALSE, + (int)wud->insets.left, (int)wud->insets.right, (int)wud->insets.top, (int)wud->insets.bottom); + } } -#endif - static void WmSize(JNIEnv *env, WindowUserData * wud, HWND wnd, UINT type) { RECT rc; BOOL isVisible = IsWindowVisible(wnd); jobject window = wud->jinstance; + BOOL maxChanged = FALSE; + + DBG_PRINT("*** WindowsWindow: WmSize.0 window %p, %dx%d, isMinimized %d, isMaximized %d, visible %d\n", + (void*)wnd, wud->width, wud->height, wud->isMinimized, wud->isMaximized, isVisible); if (type == SIZE_MINIMIZED) { - // TODO: deal with minimized window sizing + wud->isMinimized = TRUE; return; } + if (type == SIZE_MAXIMIZED) { + if( !wud->isMaximized ) { + wud->isMaximized = 1; + maxChanged = TRUE; + } + } else if (type == SIZE_RESTORED) { + wud->isMinimized = FALSE; + if( wud->isMaximized ) { + wud->isMaximized = FALSE; + maxChanged = TRUE; + } + } // make sure insets are up to date - (void)UpdateInsets(env, window, wnd); + UpdateInsets(env, wud, wnd); GetClientRect(wnd, &rc); @@ -802,9 +801,16 @@ static void WmSize(JNIEnv *env, WindowUserData * wud, HWND wnd, UINT type) wud->width = (int) ( rc.right - rc.left ); wud->height = (int) ( rc.bottom - rc.top ); - DBG_PRINT("*** WindowsWindow: WmSize window %p, %dx%d, visible %d\n", (void*)wnd, wud->width, wud->height, isVisible); + DBG_PRINT("*** WindowsWindow: WmSize.X window %p, %dx%d, isMinimized %d, isMaximized %d (changed %d), visible %d, at-init %d\n", + (void*)wnd, wud->width, wud->height, wud->isMinimized, wud->isMaximized, maxChanged, isVisible, wud->isInCreation); - (*env)->CallVoidMethod(env, window, sizeChangedID, JNI_FALSE, wud->width, wud->height, JNI_FALSE); + if( !wud->isInCreation ) { + if( maxChanged ) { + jboolean v = wud->isMaximized ? JNI_TRUE : JNI_FALSE; + (*env)->CallVoidMethod(env, window, maximizedChangedID, v, v); + } + (*env)->CallVoidMethod(env, window, sizeChangedID, JNI_FALSE, wud->width, wud->height, JNI_FALSE); + } } #ifdef TEST_MOUSE_HOOKS @@ -930,6 +936,7 @@ static void sendTouchScreenEvent(JNIEnv *env, jobject window, jNames, jX, jY, jPressure, (jfloat)maxPressure); } +// #define DO_ERASEBKGND 1 static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; @@ -993,11 +1000,15 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP // Bug 916 - NEWT Fullscreen Mode on Windows ALT-TAB doesn't allow Application Switching // Remedy for 'some' display drivers, i.e. Intel HD: // Explicitly push fullscreen window to BOTTOM when inactive (ALT-TAB) - UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; - if( inactive ) { - SetWindowPos(wnd, HWND_BOTTOM, 0, 0, 0, 0, flags); + if( inactive || wud->isOnBottom ) { + SetWindowPos(wnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); } else { - SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0, flags); + UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; + if( wud->isOnTop ) { + SetWindowPos(wnd, HWND_TOPMOST, 0, 0, 0, 0, flags); + } else { + SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0, flags); + } SetForegroundWindow(wnd); // Slightly Higher Priority } } @@ -1005,11 +1016,39 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP } break; + case WM_WINDOWPOSCHANGING: { + WINDOWPOS *p = (WINDOWPOS*)lParam; + BOOL isThis = wnd == p->hwnd; + BOOL isBottom = HWND_BOTTOM == p->hwndInsertAfter; + BOOL isTopMost = HWND_TOPMOST == p->hwndInsertAfter; + BOOL forceBottom = isThis && wud->isOnBottom && !isBottom; + BOOL forceTop = isThis && wud->isOnTop && !isTopMost; + #ifdef VERBOSE_ON + BOOL isNoTopMost = HWND_NOTOPMOST == p->hwndInsertAfter; + BOOL isTop = HWND_TOP == p->hwndInsertAfter; + BOOL isNoZ = 0 != ( SWP_NOZORDER & p->flags ); + DBG_PRINT("*** WindowsWindow: WM_WINDOWPOSCHANGING window %p / %p (= %d), %p[bottom %d, notop %d, top %d, topmost %d, noZ %d, force[Top %d, Bottom %d], %d/%d %dx%d 0x%X\n", + wnd, p->hwnd, isThis, + p->hwndInsertAfter, isBottom, isNoTopMost, isTop, isTopMost, isNoZ, + forceTop, forceBottom, + p->x, p->y, p->cx, p->cy, p->flags); + #endif + if( forceTop ) { + p->hwndInsertAfter = HWND_TOPMOST; + p->flags &= ~SWP_NOZORDER; + } else if( forceBottom ) { + p->hwndInsertAfter = HWND_BOTTOM; + p->flags &= ~SWP_NOZORDER; + } + useDefWindowProc = 1; + } + break; + case WM_SETTINGCHANGE: if (wParam == SPI_SETNONCLIENTMETRICS) { // make sure insets are updated, we don't need to resize the window // because the size of the client area doesn't change - (void)UpdateInsets(env, window, wnd); + UpdateInsets(env, wud, wnd); } else { useDefWindowProc = 1; } @@ -1020,32 +1059,79 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_SHOWWINDOW: - (*env)->CallVoidMethod(env, window, visibleChangedID, JNI_FALSE, wParam==TRUE?JNI_TRUE:JNI_FALSE); + DBG_PRINT("*** WindowsWindow: WM_SHOWWINDOW window %p: %d, at-init %d\n", wnd, wParam==TRUE, wud->isInCreation); + wud->visible = wParam==TRUE; + if( !wud->isInCreation ) { + (*env)->CallVoidMethod(env, window, visibleChangedID, JNI_FALSE, wParam==TRUE?JNI_TRUE:JNI_FALSE); + } break; case WM_MOVE: - 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)); + wud->xpos = (int)GET_X_LPARAM(lParam); + wud->ypos = (int)GET_Y_LPARAM(lParam); + DBG_PRINT("*** WindowsWindow: WM_MOVE window %p, %d/%d, at-init %d\n", wnd, wud->xpos, wud->ypos, wud->isInCreation); + if( !wud->isInCreation ) { + (*env)->CallVoidMethod(env, window, positionChangedID, JNI_FALSE, (jint)wud->xpos, (jint)wud->ypos); + } useDefWindowProc = 1; break; case WM_PAINT: { - RECT r; - if (GetUpdateRect(wnd, &r, FALSE /* do not erase background */)) { - // clear the whole client area and issue repaint for it, w/o looping through erase background - ValidateRect(wnd, NULL); // clear all! - (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); + if( wud->isInCreation ) { + #ifdef DO_ERASEBKGND + if (GetUpdateRect(wnd, NULL, TRUE /* erase background */)) { + DBG_PRINT("*** WindowsWindow: WM_PAINT.0 (dirty)\n"); + // WM_ERASEBKGND sent! + #else + if (GetUpdateRect(wnd, NULL, FALSE /* do not erase background */)) { + DBG_PRINT("*** WindowsWindow: WM_PAINT.0 (dirty)\n"); + ValidateRect(wnd, NULL); // clear all! + #endif + } else { + DBG_PRINT("*** WindowsWindow: WM_PAINT.0 (clean)\n"); + } } else { - // shall not happen ? - ValidateRect(wnd, NULL); // clear all! + if (GetUpdateRect(wnd, NULL, FALSE /* do not erase background */)) { + DBG_PRINT("*** WindowsWindow: WM_PAINT.1 (dirty)\n"); + // Let NEWT render the whole client area by issueing repaint for it, w/o looping through erase background + ValidateRect(wnd, NULL); // clear all! + (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); + } else { + DBG_PRINT("*** WindowsWindow: WM_PAINT.1 (clean)\n"); + // shall not happen ? + ValidateRect(wnd, NULL); // clear all! + } + // return 0 == done } - // return 0 == done break; } case WM_ERASEBKGND: - // ignore erase background - (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); - res = 1; // return 1 == done, OpenGL, etc .. erases the background, hence we claim to have just done this + if( wud->isInCreation ) { + #ifdef DO_ERASEBKGND + // On Windows the initial window is clean?! + // This fill destroys translucency on Windows 10 + // (which only seem to work on undecorated windows) + PAINTSTRUCT ps; + HDC hdc; + hdc = BeginPaint(wnd, &ps); + DBG_PRINT("*** WindowsWindow: WM_ERASEBKGND.0 (erasure) l/b %d/%d r/t %d/%d\n", + ps.rcPaint.left, ps.rcPaint.bottom, ps.rcPaint.right, ps.rcPaint.top); + // FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW+1)); + // FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_APPWORKSPACE+1)); + // A black color also sets alpha to zero for translucency! + FillRect(hdc, &ps.rcPaint, (HBRUSH)GetStockObject(BLACK_PEN)); + EndPaint(wnd, &ps); + #else + ValidateRect(wnd, NULL); // clear all! + #endif + res = 1; // return 1 == done + } else { + // ignore erase background, but let NEWT render the whole client area + DBG_PRINT("*** WindowsWindow: WM_ERASEBKGND.1 (repaint)\n"); + ValidateRect(wnd, NULL); // clear all! + (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); + res = 1; // return 1 == done, OpenGL, etc .. erases the background, hence we claim to have just done this + } break; case WM_SETCURSOR : @@ -1094,8 +1180,11 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP break; case WM_SETFOCUS: - DBG_PRINT("*** WindowsWindow: WM_SETFOCUS window %p, lost %p\n", wnd, (HWND)wParam); - (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_TRUE); + DBG_PRINT("*** WindowsWindow: WM_SETFOCUS window %p, lost %p, at-init %d\n", wnd, (HWND)wParam, wud->isInCreation); + wud->focused = TRUE; + if( !wud->isInCreation ) { + (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_TRUE); + } useDefWindowProc = 1; break; @@ -1108,7 +1197,10 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lP wud->pointerCaptured = 0; ReleaseCapture(); } - (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_FALSE); + wud->focused = FALSE; + if( !wud->isInCreation ) { + (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_FALSE); + } useDefWindowProc = 1; } else { // quick focus .. we had it already, are enabled .. @@ -2032,9 +2124,11 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); + maximizedChangedID = (*env)->GetMethodID(env, clazz, "maximizedChanged", "(ZZ)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"); + sizePosInsetsFocusVisibleChangedID = (*env)->GetMethodID(env, clazz, "sizePosInsetsFocusVisibleChanged", "(ZIIIIIIIIIIZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(SIIISF)V"); @@ -2044,9 +2138,11 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 if (insetsChangedID == NULL || sizeChangedID == NULL || + maximizedChangedID == NULL || positionChangedID == NULL || focusChangedID == NULL || visibleChangedID == NULL || + sizePosInsetsFocusVisibleChangedID == NULL || windowDestroyNotifyID == NULL || windowRepaintID == NULL || sendMouseEventID == NULL || @@ -2088,32 +2184,61 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_getNewtWndP return (jlong) (intptr_t) wndProc; } -static void NewtWindow_setVisiblePosSize(HWND hwnd, BOOL atop, BOOL visible, +static void NewtWindow_setVisiblePosSize(WindowUserData *wud, HWND hwnd, int jflags, BOOL visible, int x, int y, int width, int height) { - UINT flags; - BOOL bRes; - - DBG_PRINT("*** WindowsWindow: NewtWindow_setVisiblePosSize %d/%d %dx%d, atop %d, visible %d\n", - x, y, width, height, atop, visible); + BOOL atop = TST_FLAG_IS_ALWAYSONTOP(jflags); + BOOL abottom = TST_FLAG_IS_ALWAYSONBOTTOM(jflags); + UINT wflags; + + DBG_PRINT("*** WindowsWindow: NewtWindow_setVisiblePosSize client %d/%d %dx%d, atop %d, abottom %d, max[change[%d %d], is[%d %d]], visible %d\n", + x, y, width, height, atop, abottom, + TST_FLAG_CHANGE_MAXIMIZED_VERT(jflags), TST_FLAG_CHANGE_MAXIMIZED_HORZ(jflags), + TST_FLAG_IS_MAXIMIZED_VERT(jflags), TST_FLAG_IS_MAXIMIZED_HORZ(jflags), + visible); + + x -= wud->insets.left; // top-level + y -= wud->insets.top; // top-level + width += wud->insets.left + wud->insets.right; // top-level + height += wud->insets.top + wud->insets.bottom; // top-level + DBG_PRINT("*** WindowsWindow: NewtWindow_setVisiblePosSize top-level %d/%d %dx%d\n", x, y, width, height); if(visible) { - flags = SWP_SHOWWINDOW; + wflags = SWP_SHOWWINDOW; + if( abottom ) { + wflags |= SWP_NOACTIVATE; + } } else { - flags = SWP_NOACTIVATE | SWP_NOZORDER; + wflags = SWP_NOACTIVATE | SWP_NOZORDER; } if(0>=width || 0>=height ) { - flags |= SWP_NOSIZE; + wflags |= SWP_NOSIZE; } + wud->isOnTop = atop; + wud->isOnBottom = abottom; if(atop) { - SetWindowPos(hwnd, HWND_TOP, x, y, width, height, flags); - SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, flags); + SetWindowPos(hwnd, HWND_TOP, x, y, width, height, wflags); + SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, wflags); + } else if(abottom) { + SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, width, height, wflags); + SetWindowPos(hwnd, HWND_BOTTOM, x, y, width, height, wflags); } else { - SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, width, height, flags); - SetWindowPos(hwnd, HWND_TOP, x, y, width, height, flags); + SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, width, height, wflags); + SetWindowPos(hwnd, HWND_TOP, x, y, width, height, wflags); + } + + if( TST_FLAG_CHANGE_MAXIMIZED_ANY(jflags) ) { + if( TST_FLAG_IS_MAXIMIZED_VERT(jflags) && TST_FLAG_IS_MAXIMIZED_HORZ(jflags) ) { + wud->isMaximized = 1; + ShowWindow(hwnd, SW_MAXIMIZE); + } else if( !TST_FLAG_IS_MAXIMIZED_VERT(jflags) && !TST_FLAG_IS_MAXIMIZED_HORZ(jflags) ) { + if( wud->isMaximized ) { + ShowWindow(hwnd, SW_RESTORE); + wud->isMaximized = 0; + } + } } - // SetWindowPos(hwnd, atop ? HWND_TOPMOST : HWND_TOP, x, y, width, height, flags); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); @@ -2128,16 +2253,15 @@ static void NewtWindow_setVisiblePosSize(HWND hwnd, BOOL atop, BOOL visible, JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindow0 (JNIEnv *env, jobject obj, jlong hInstance, jstring jWndClassName, jstring jWndName, jint winMajor, jint winMinor, - jlong parent, jint jx, jint jy, jint defaultWidth, jint defaultHeight, jboolean autoPosition, jint flags) + jlong parent, jint jxpos, jint jypos, jint defaultWidth, jint defaultHeight, jint flags) { HWND parentWindow = (HWND) (intptr_t) parent; const TCHAR* wndClassName = NULL; const TCHAR* wndName = NULL; - DWORD windowStyle = WS_DEFAULT_STYLES | WS_VISIBLE; - int x=(int)jx, y=(int)jy; + DWORD windowStyle = WS_DEFAULT_STYLES; + int xpos=(int)jxpos, ypos=(int)jypos; int width=(int)defaultWidth, height=(int)defaultHeight; - HWND window = NULL; - int _x = x, _y = y; // pos for CreateWindow, might be tweaked + HWND hwnd = NULL; #ifdef UNICODE wndClassName = NewtCommon_GetNullTerminatedStringChars(env, jWndClassName); @@ -2153,43 +2277,54 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo return 0; } windowStyle |= WS_CHILD ; - } else if ( TST_FLAG_IS_UNDECORATED(flags) ) { - windowStyle |= WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; } else { - windowStyle |= WS_OVERLAPPEDWINDOW; - if(JNI_TRUE == autoPosition) { + if ( TST_FLAG_IS_UNDECORATED(flags) ) { + windowStyle |= WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; + } else if ( TST_FLAG_IS_RESIZABLE(flags) ) { + // WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + windowStyle |= WS_OVERLAPPEDWINDOW; + } else { + windowStyle |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + } + if( TST_FLAG_IS_AUTOPOSITION(flags) ) { // user didn't requested specific position, use WM default - _x = CW_USEDEFAULT; - _y = 0; + xpos = CW_USEDEFAULT; + ypos = 0; } } - window = CreateWindow(wndClassName, wndName, windowStyle, - _x, _y, width, height, - parentWindow, NULL, - (HINSTANCE) (intptr_t) hInstance, - NULL); + hwnd = CreateWindow(wndClassName, wndName, windowStyle, + xpos, ypos, width, height, + parentWindow, NULL, (HINSTANCE) (intptr_t) hInstance, NULL); - DBG_PRINT("*** WindowsWindow: CreateWindow thread 0x%X, win %d.%d parent %p, window %p, %d/%d %dx%d, undeco %d, alwaysOnTop %d, autoPosition %d\n", - (int)GetCurrentThreadId(), winMajor, winMinor, parentWindow, window, x, y, width, height, - TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags), autoPosition); + DBG_PRINT("*** WindowsWindow: CreateWindow thread 0x%X, win %d.%d parent %p, window %p, %d/%d -> %d/%d %dx%d, undeco %d, alwaysOnTop %d, autoPosition %d\n", + (int)GetCurrentThreadId(), winMajor, winMinor, parentWindow, hwnd, jxpos, jypos, xpos, ypos, width, height, + TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags), TST_FLAG_IS_AUTOPOSITION(flags)); - if (NULL == window) { + if (NULL == hwnd) { int lastError = (int) GetLastError(); DBG_PRINT("*** WindowsWindow: CreateWindow failure: 0x%X %d\n", lastError, lastError); - return 0; } else { WindowUserData * wud = (WindowUserData *) malloc(sizeof(WindowUserData)); wud->jinstance = (*env)->NewGlobalRef(env, obj); wud->jenv = env; + wud->xpos = xpos; + wud->ypos = ypos; wud->width = width; wud->height = height; + wud->visible = TRUE; + wud->focused = TRUE; wud->setPointerVisible = 0; wud->setPointerAction = 0; wud->defPointerHandle = LoadCursor( NULL, IDC_ARROW); wud->setPointerHandle = wud->defPointerHandle; - wud->isFullscreen = 0; + wud->isFullscreen = FALSE; wud->isChildWindow = NULL!=parentWindow; + wud->isMinimized = FALSE; + wud->isMaximized = FALSE; + wud->isOnBottom = FALSE; + wud->isOnTop = FALSE; + wud->isInCreation = TRUE; wud->pointerCaptured = 0; wud->pointerInside = 0; wud->touchDownCount = 0; @@ -2208,40 +2343,26 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo DBG_PRINT("*** WindowsWindow: CreateWindow winTouchFuncAvail %d, supportsMTouch %d\n", WinTouch_func_avail, wud->supportsMTouch); #if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) - SetWindowLong(window, GWL_USERDATA, (intptr_t) wud); + SetWindowLong(hwnd, GWL_USERDATA, (intptr_t) wud); #else - SetWindowLongPtr(window, GWLP_USERDATA, (intptr_t) wud); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (intptr_t) wud); #endif - // gather and adjust position and size - { - RECT rc; - RECT * insets; - - ShowWindow(window, SW_SHOW); - - // send insets before visibility, allowing java code a proper sync point! - insets = UpdateInsets(env, wud->jinstance, window); - (*env)->CallVoidMethod(env, wud->jinstance, visibleChangedID, JNI_FALSE, JNI_TRUE); - - 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 (autoPosition %d)\n", x, y, width, height, autoPosition); + // send insets before visibility, allowing java code a proper sync point! + UpdateInsets(env, wud, hwnd); - x -= insets->left; // top-level - y -= insets->top; // top-level - width += insets->left + insets->right; // top-level - height += insets->top + insets->bottom; // top-level - DBG_PRINT("*** WindowsWindow: CreateWindow top-level %d/%d %dx%d\n", x, y, width, height); - - NewtWindow_setVisiblePosSize(window, TST_FLAG_IS_ALWAYSONTOP(flags), TRUE, x, y, width, height); - } - if( wud->supportsMTouch ) { - WinTouch_RegisterTouchWindow(window, 0); + if( TST_FLAG_IS_AUTOPOSITION(flags) ) { + RECT rc; + GetWindowRect(hwnd, &rc); + xpos = rc.left + wud->insets.left; // client coords + ypos = rc.top + wud->insets.top; // client coords + wud->xpos = xpos; + wud->ypos = ypos; } + DBG_PRINT("*** WindowsWindow: CreateWindow client: %d/%d %dx%d -> %d/%d %dx%d (autoPosition %d)\n", + xpos, ypos, width, height, + wud->xpos, wud->ypos, wud->width, wud->height, + TST_FLAG_IS_AUTOPOSITION(flags)); } #ifdef UNICODE @@ -2258,7 +2379,49 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo DBG_PRINT("**** LLMP Hook %p, MP Hook %p\n", hookLLMP, hookMP); #endif - return (jlong) (intptr_t) window; + DBG_PRINT("*** WindowsWindow: CreateWindow done\n"); + return (jlong) (intptr_t) hwnd; +} + +/* + * Class: jogamp_newt_driver_windows_WindowDriver + * Method: InitWindow + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_InitWindow0 + (JNIEnv *env, jobject obj, jlong window, jint flags) +{ + HWND hwnd = (HWND) (intptr_t) window; + WindowUserData * wud; +#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) + wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA); +#else + wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#endif + + DBG_PRINT("*** WindowsWindow: InitWindow start %d/%d %dx%d, focused %d, visible %d\n", + wud->xpos, wud->ypos, wud->width, wud->height, wud->focused, wud->visible); + + NewtWindow_setVisiblePosSize(wud, hwnd, flags, TRUE, wud->xpos, wud->ypos, wud->width, wud->height); + wud->isInCreation = FALSE; + + DBG_PRINT("*** WindowsWindow: InitWindow pos/size set: %d/%d %dx%d, focused %d, visible %d\n", + wud->xpos, wud->ypos, wud->width, wud->height, wud->focused, wud->visible); + + if( wud->isMaximized ) { + (*env)->CallVoidMethod(env, wud->jinstance, maximizedChangedID, JNI_TRUE, JNI_TRUE); + } + (*env)->CallVoidMethod(env, wud->jinstance, sizePosInsetsFocusVisibleChangedID, JNI_FALSE, + (jint)wud->xpos, (jint)wud->ypos, + (jint)wud->width, (jint)wud->height, + (jint)wud->insets.left, (jint)wud->insets.right, (jint)wud->insets.top, (jint)wud->insets.bottom, + (jint)(wud->focused ? 1 : 0), + (jint)(wud->visible ? 1 : 0), + JNI_FALSE); + DBG_PRINT("*** WindowsWindow: InitWindow JNI callbacks done\n"); + + if( wud->supportsMTouch ) { + WinTouch_RegisterTouchWindow(hwnd, 0); + } } /* @@ -2288,7 +2451,10 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW HWND hwndP = (HWND) (intptr_t) parent; HWND hwnd = (HWND) (intptr_t) window; DWORD windowStyle = WS_DEFAULT_STYLES; - BOOL styleChange = TST_FLAG_CHANGE_DECORATION(flags) || TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_PARENTING(flags) ; + BOOL styleChange = TST_FLAG_CHANGE_DECORATION(flags) || TST_FLAG_CHANGE_FULLSCREEN(flags) || + TST_FLAG_CHANGE_PARENTING(flags) || TST_FLAG_CHANGE_RESIZABLE(flags); + BOOL atop = TST_FLAG_IS_ALWAYSONTOP(flags); + BOOL abottom = TST_FLAG_IS_ALWAYSONBOTTOM(flags); WindowUserData * wud; #if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA); @@ -2296,20 +2462,25 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); #endif - - DBG_PRINT( "*** WindowsWindow: reconfigureWindow0 parent %p, window %p, %d/%d %dx%d, parentChange %d, isChild %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d -> styleChange %d, isChild %d, isFullscreen %d\n", + DBG_PRINT( "*** WindowsWindow: reconfigureWindow0 parent %p, window %p, %d/%d %dx%d, parentChange %d, isChild %d, undecoration[change %d, val %d], fullscreen[change %d, val %d], alwaysOnTop[change %d, val %d], alwaysOnBottom[change %d, val %d], visible[change %d, val %d], resizable[change %d, val %d] -> styleChange %d, isChild %d, isMinimized %d, isMaximized %d, isFullscreen %d\n", parent, window, x, y, width, height, TST_FLAG_CHANGE_PARENTING(flags), TST_FLAG_IS_CHILD(flags), TST_FLAG_CHANGE_DECORATION(flags), TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_CHANGE_FULLSCREEN(flags), TST_FLAG_IS_FULLSCREEN(flags), TST_FLAG_CHANGE_ALWAYSONTOP(flags), TST_FLAG_IS_ALWAYSONTOP(flags), - TST_FLAG_CHANGE_VISIBILITY(flags), TST_FLAG_IS_VISIBLE(flags), styleChange, wud->isChildWindow, wud->isFullscreen); + TST_FLAG_CHANGE_ALWAYSONBOTTOM(flags), TST_FLAG_IS_ALWAYSONBOTTOM(flags), + TST_FLAG_CHANGE_VISIBILITY(flags), TST_FLAG_IS_VISIBLE(flags), + TST_FLAG_CHANGE_RESIZABLE(flags), TST_FLAG_CHANGE_RESIZABLE(flags), styleChange, + wud->isChildWindow, wud->isMinimized, wud->isMaximized, wud->isFullscreen); if (!IsWindow(hwnd)) { DBG_PRINT("*** WindowsWindow: reconfigureWindow0 failure: Passed window %p is invalid\n", (void*)hwnd); return; } + wud->isOnTop = atop; + wud->isOnBottom = abottom; + if (NULL!=hwndP && !IsWindow(hwndP)) { DBG_PRINT("*** WindowsWindow: reconfigureWindow0 failure: Passed parent window %p is invalid\n", (void*)hwndP); return; @@ -2334,10 +2505,15 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW SetParent(hwnd, NULL); } - if( TST_FLAG_CHANGE_FULLSCREEN(flags) && TST_FLAG_IS_FULLSCREEN(flags) ) { // FS on - // TOP: in -> out - wud->isFullscreen = 1; - NewtWindows_setFullScreen(JNI_TRUE); + if( TST_FLAG_IS_FULLSCREEN(flags) ) { + if( TST_FLAG_CHANGE_FULLSCREEN(flags) ) { // FS on + wud->isFullscreen = TRUE; + if( !abottom ) { + NewtWindows_setFullScreen(JNI_TRUE); + } + } else if( TST_FLAG_CHANGE_ALWAYSONBOTTOM(flags) ) { // FS BOTTOM toggle + NewtWindows_setFullScreen( abottom ? JNI_FALSE : JNI_TRUE); + } } if ( styleChange ) { @@ -2345,16 +2521,18 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW windowStyle |= WS_CHILD ; } else if ( TST_FLAG_IS_UNDECORATED(flags) ) { windowStyle |= WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; - } else { + } else if ( TST_FLAG_IS_RESIZABLE(flags) ) { + // WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); windowStyle |= WS_OVERLAPPEDWINDOW; + } else { + windowStyle |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; } SetWindowLong(hwnd, GWL_STYLE, windowStyle); SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER ); } if( TST_FLAG_CHANGE_FULLSCREEN(flags) && !TST_FLAG_IS_FULLSCREEN(flags) ) { // FS off - // CHILD: out -> in - wud->isFullscreen = 0; + wud->isFullscreen = FALSE; NewtWindows_setFullScreen(JNI_FALSE); } @@ -2363,17 +2541,25 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW SetParent(hwnd, hwndP ); } - NewtWindow_setVisiblePosSize(hwnd, TST_FLAG_IS_ALWAYSONTOP(flags), TST_FLAG_IS_VISIBLE(flags), x, y, width, height); + NewtWindow_setVisiblePosSize(wud, hwnd, flags, TST_FLAG_IS_VISIBLE(flags), x, y, width, height); if( TST_FLAG_CHANGE_VISIBILITY(flags) ) { if( TST_FLAG_IS_VISIBLE(flags) ) { - ShowWindow(hwnd, SW_SHOW); + int cmd = wud->isMinimized ? SW_RESTORE : ( abottom ? SW_SHOWNA : SW_SHOW ); + wud->isMinimized = FALSE; + ShowWindow(hwnd, cmd); + if( abottom ) { + SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + } + } else if( !TST_FLAG_CHANGE_VISIBILITY_FAST(flags) && !TST_FLAG_IS_CHILD(flags) ) { + wud->isMinimized = TRUE; + ShowWindow(hwnd, SW_MINIMIZE); } else { ShowWindow(hwnd, SW_HIDE); } } - DBG_PRINT("*** WindowsWindow: reconfigureWindow0.X isChild %d, isFullscreen %d\n", wud->isChildWindow, wud->isFullscreen); + DBG_PRINT("*** WindowsWindow: reconfigureWindow0.X isChild %d, isMinimized %d, isFullscreen %d\n", wud->isChildWindow, wud->isMinimized, wud->isFullscreen); } /* diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h index 309e62683..f9254ab76 100644 --- a/src/newt/native/X11Common.h +++ b/src/newt/native/X11Common.h @@ -71,7 +71,7 @@ extern jclass X11NewtWindowClazz; extern jmethodID insetsChangedID; extern jmethodID visibleChangedID; -extern jmethodID minMaxSizeChangedID; +extern jmethodID insetsVisibleChangedID; typedef struct { Window window; @@ -81,13 +81,71 @@ typedef struct { Atom windowDeleteAtom; uint32_t supportedAtoms; uint32_t lastDesktop; + Bool maxHorz; + Bool maxVert; + /** flag whether window is mapped */ + Bool isMapped; } JavaWindow; JavaWindow * getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); -Status NewtWindows_updateInsets(JNIEnv *env, Display *dpy, JavaWindow * w, int *left, int *right, int *top, int *bottom); -void NewtWindows_updateMinMaxSize(JNIEnv *env, Display *dpy, JavaWindow * w); +Bool NewtWindows_updateInsets(Display *dpy, JavaWindow * w, int *left, int *right, int *top, int *bottom); +Bool NewtWindows_updateMaximized(Display *dpy, JavaWindow * w, uint32_t netWMState); + +#define _MASK_NET_WM_STATE ( 1 << 0 ) +#define _MASK_NET_WM_STATE_MODAL ( 1 << 1 ) +#define _MASK_NET_WM_STATE_STICKY ( 1 << 2 ) +#define _MASK_NET_WM_STATE_MAXIMIZED_VERT ( 1 << 3 ) +#define _MASK_NET_WM_STATE_MAXIMIZED_HORZ ( 1 << 4 ) +#define _MASK_NET_WM_STATE_SHADED ( 1 << 5 ) +#define _MASK_NET_WM_STATE_HIDDEN ( 1 << 8 ) +#define _MASK_NET_WM_STATE_FULLSCREEN ( 1 << 9 ) +#define _MASK_NET_WM_STATE_ABOVE ( 1 << 10 ) +#define _MASK_NET_WM_STATE_BELOW ( 1 << 11 ) +#define _MASK_NET_WM_STATE_DEMANDS_ATTENTION ( 1 << 12 ) +#define _MASK_NET_WM_STATE_FOCUSED ( 1 << 13 ) +#define _MASK_NET_WM_BYPASS_COMPOSITOR ( 1 << 14 ) +#define _MASK_NET_WM_DESKTOP ( 1 << 15 ) +#define _MASK_NET_CURRENT_DESKTOP ( 1 << 16 ) +#define _MASK_NET_WM_WINDOW_TYPE ( 1 << 17 ) +#define _MASK_NET_WM_WINDOW_TYPE_NORMAL ( 1 << 18 ) +#define _MASK_NET_WM_WINDOW_TYPE_POPUP_MENU ( 1 << 19 ) +#define _MASK_NET_FRAME_EXTENTS ( 1 << 20 ) +#define _MASK_NET_SUPPORTED ( 1 << 21 ) +#define _MASK_NET_ACTIVE_WINDOW ( 1 << 22 ) +#define _MASK_WM_CHANGE_STATE ( 1 << 23 ) +#define _MASK_MOTIF_WM_HINTS ( 1 << 24 ) + +#define _NET_WM_STATE_IDX 0 +#define _NET_WM_STATE_MODAL_IDX 1 +#define _NET_WM_STATE_STICKY_IDX 2 +#define _NET_WM_STATE_MAXIMIZED_VERT_IDX 3 +#define _NET_WM_STATE_MAXIMIZED_HORZ_IDX 4 +#define _NET_WM_STATE_SHADED_IDX 5 +#define _NET_WM_STATE_SKIP_TASKBAR_IDX 6 +#define _NET_WM_STATE_SKIP_PAGER_IDX 7 +#define _NET_WM_STATE_HIDDEN_IDX 8 +#define _NET_WM_STATE_FULLSCREEN_IDX 9 +#define _NET_WM_STATE_ABOVE_IDX 10 +#define _NET_WM_STATE_BELOW_IDX 11 +#define _NET_WM_STATE_DEMANDS_ATTENTION_IDX 12 +#define _NET_WM_STATE_FOCUSED_IDX 13 +#define _NET_WM_BYPASS_COMPOSITOR_IDX 14 +#define _NET_WM_DESKTOP_IDX 15 +#define _NET_CURRENT_DESKTOP_IDX 16 +#define _NET_WM_WINDOW_TYPE_IDX 17 +#define _NET_WM_WINDOW_TYPE_NORMAL_IDX 18 +#define _NET_WM_WINDOW_TYPE_POPUP_MENU_IDX 19 +#define _NET_FRAME_EXTENTS_IDX 20 +#define _NET_SUPPORTED_IDX 21 +#define _NET_ACTIVE_WINDOW_IDX 22 +#define _WM_CHANGE_STATE_IDX 23 +#define _MOTIF_WM_HINTS_IDX 24 + +void NewtWindows_setUrgency(Display *dpy, Window window, Bool enable); +void NewtWindows_sendNET_WM_STATE(Display *dpy, Window root, JavaWindow *w, int prop1Idx, int prop2Idx, Bool enable); +uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, JavaWindow *w); #endif /* _X11COMMON_H_ */ diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 0ba454a00..32e0f8786 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -35,7 +35,7 @@ jclass X11NewtWindowClazz = NULL; jmethodID insetsChangedID = NULL; jmethodID visibleChangedID = NULL; -jmethodID minMaxSizeChangedID = NULL; +jmethodID insetsVisibleChangedID = NULL; static const char * const ClazzNameX11NewtWindow = "jogamp/newt/driver/x11/WindowDriver"; @@ -46,13 +46,16 @@ static jmethodID getCurrentThreadNameID = NULL; static jmethodID dumpStackID = NULL; static jmethodID sizeChangedID = NULL; static jmethodID positionChangedID = NULL; -static jmethodID focusChangedID = NULL; +static jmethodID focusVisibleChangedID = NULL; static jmethodID reparentNotifyID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowRepaintID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID requestFocusID = NULL; +static jmethodID sendMouseEventRequestFocusID = NULL; +static jmethodID visibleChangedWindowRepaintID = NULL; +static jmethodID visibleChangedSendMouseEventID = NULL; +static jmethodID sizePosMaxInsetsVisibleChangedID = NULL; /** * Keycode @@ -222,7 +225,7 @@ static jint X11InputState2NewtModifiers(unsigned int xstate, jshort javaVKey, jb /* * Class: jogamp_newt_driver_x11_DisplayDriver - * Method: initIDs + * Method: initIDs0 * Signature: (Z)Z */ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 @@ -252,15 +255,18 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 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"); + focusVisibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "focusVisibleChanged", "(ZII)V"); visibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChanged", "(ZZ)V"); - minMaxSizeChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "minMaxSizeChanged", "(IIII)V"); + insetsVisibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "insetsVisibleChanged", "(ZIIIII)V"); + sizePosMaxInsetsVisibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sizePosMaxInsetsVisibleChanged", "(ZIIIIIIIIIIIZ)V"); reparentNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "reparentNotify", "(J)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowRepaint", "(ZIIII)V"); + visibleChangedWindowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChangedWindowRepaint", "(ZIIIII)V"); sendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEvent", "(SIIISF)V"); + sendMouseEventRequestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEventRequestFocus", "(SIIISF)V"); + visibleChangedSendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChangedSendMouseEvent", "(ZISIIISF)V"); sendKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendKeyEvent", "(SISSCLjava/lang/String;)V"); - requestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "requestFocus", "(Z)V"); if (displayCompletedID == NULL || sendRRScreenChangeNotifyID == NULL || @@ -269,15 +275,18 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 insetsChangedID == NULL || sizeChangedID == NULL || positionChangedID == NULL || - focusChangedID == NULL || + focusVisibleChangedID == NULL || visibleChangedID == NULL || - minMaxSizeChangedID == NULL || + insetsVisibleChangedID == NULL || + sizePosMaxInsetsVisibleChangedID == NULL || reparentNotifyID == NULL || windowDestroyNotifyID == NULL || windowRepaintID == NULL || + visibleChangedWindowRepaintID == NULL || sendMouseEventID == NULL || - sendKeyEventID == NULL || - requestFocusID == NULL) { + sendMouseEventRequestFocusID == NULL || + visibleChangedSendMouseEventID == NULL || + sendKeyEventID == NULL) { return JNI_FALSE; } @@ -287,7 +296,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 /* * Class: jogamp_newt_driver_x11_DisplayDriver - * Method: CompleteDisplay + * Method: CompleteDisplay0 * Signature: (J)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_CompleteDisplay0 @@ -353,10 +362,33 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DisplayRelease0 DBG_PRINT("X11: X11Display_DisplayRelease dpy %p\n", dpy); } +static int NewtWindows_updateVisibility(JNIEnv *env, Display *dpy, JavaWindow *jw, uint32_t netWMState, const char *dbgs) { + int visibleChange; + if( jw->isMapped && 0 != ( _MASK_NET_WM_STATE_HIDDEN & jw->supportedAtoms ) ) { + if( 0 != ( _MASK_NET_WM_STATE_HIDDEN & netWMState ) ) { + visibleChange = 0; + } else { + visibleChange = 1; + } + } else { + visibleChange = -1; + } + #ifdef VERBOSE_ON + XWindowAttributes xwa; + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, jw->window, &xwa); + + // map_state: IsUnmapped(0), IsUnviewable(1), IsViewable(2) + DBG_PRINT( "X11: event . %s call %p - isMapped %d, visibleChanged %d, map_state %d\n", + dbgs, (void*)jw->window, jw->isMapped, visibleChange, xwa.map_state); + #endif + return visibleChange; +} + /* * Class: jogamp_newt_driver_x11_DisplayDriver - * Method: DispatchMessages - * Signature: (JJJ)V + * Method: DispatchMessages0 + * Signature: (JJJII)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0 (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/, @@ -522,8 +554,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage switch(evt.type) { case ButtonPress: - (*env)->CallVoidMethod(env, jw->jwindow, requestFocusID, JNI_FALSE); - (*env)->CallVoidMethod(env, jw->jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_PRESSED, + (*env)->CallVoidMethod(env, jw->jwindow, sendMouseEventRequestFocusID, (jshort) EVENT_MOUSE_PRESSED, modifiers, (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jshort) evt.xbutton.button, 0.0f /*rotation*/); break; @@ -539,15 +570,23 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage break; case EnterNotify: DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - (*env)->CallVoidMethod(env, jw->jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_ENTERED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + { + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "EnterNotify"); + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedSendMouseEventID, JNI_FALSE, (jint)visibleChange, + (jshort) EVENT_MOUSE_ENTERED, modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + } break; case LeaveNotify: DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - (*env)->CallVoidMethod(env, jw->jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_EXITED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + { + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "LeaveNotify"); + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedSendMouseEventID, JNI_FALSE, (jint)visibleChange, + (jshort) EVENT_MOUSE_EXITED, modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + } break; case MappingNotify: DBG_PRINT( "X11: event . MappingNotify call %p type %d\n", (void*)evt.xmapping.window, evt.xmapping.type); @@ -579,19 +618,25 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage 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, dpy, jw, &left, &right, &top, &bottom); - } - NewtWindows_updateMinMaxSize(env, dpy, jw); - (*env)->CallVoidMethod(env, jw->jwindow, sizeChangedID, JNI_FALSE, - (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE); - (*env)->CallVoidMethod(env, jw->jwindow, positionChangedID, JNI_FALSE, - (jint) evt.xconfigure.x, (jint) evt.xconfigure.y); + // insets: negative values are ignored + int left=-1, right=-1, top=-1, bottom=-1; + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "ConfigureNotify"); + NewtWindows_updateInsets(dpy, jw, &left, &right, &top, &bottom); + Bool maxChanged = NewtWindows_updateMaximized(dpy, jw, netWMState); + (*env)->CallVoidMethod(env, jw->jwindow, sizePosMaxInsetsVisibleChangedID, JNI_FALSE, + (jint) evt.xconfigure.x, (jint) evt.xconfigure.y, + (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, + (jint)(maxChanged ? ( jw->maxHorz ? 1 : 0 ) : -1), + (jint)(maxChanged ? ( jw->maxVert ? 1 : 0 ) : -1), + (jint)left, (jint)right, (jint)top, (jint)bottom, + (jint)visibleChange, + JNI_FALSE); } break; case ClientMessage: + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X, sendEvent %d\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type, evt.xclient.send_event); if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom jboolean closed; DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X ..\n", @@ -605,46 +650,76 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage break; case FocusIn: - DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window); - (*env)->CallVoidMethod(env, jw->jwindow, focusChangedID, JNI_FALSE, JNI_TRUE); + DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xfocus.window); + { + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "FocusIn"); + (*env)->CallVoidMethod(env, jw->jwindow, focusVisibleChangedID, JNI_FALSE, (jint)1, (jint)visibleChange); + } break; case FocusOut: - DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window); - (*env)->CallVoidMethod(env, jw->jwindow, focusChangedID, JNI_FALSE, JNI_FALSE); + DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xfocus.window); + { + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "FocusOut"); + (*env)->CallVoidMethod(env, jw->jwindow, focusVisibleChangedID, JNI_FALSE, (jint)0, (jint)visibleChange); + } + break; + + case VisibilityNotify: + DBG_PRINT( "X11: event . VisibilityNotify call %p\n", (void*)evt.xvisibility.window); + { + #if 0 + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "VisibilityNotify"); + if( 0 <= visibleChange ) { + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedID, JNI_FALSE, 0 < visibleChange ? JNI_TRUE : JNI_FALSE); + } + #endif + } 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, jw->jwindow, windowRepaintID, JNI_FALSE, evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); + #if 0 + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "Expose"); + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedWindowRepaintID, JNI_FALSE, (jint)visibleChange, + evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); + #endif } 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, + DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, isMapped %d -> 1, override_redirect %d, child-event: %d\n", + (void*)evt.xmap.event, (void*)evt.xmap.window, jw->isMapped, (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, dpy, jw, &left, &right, &top, &bottom); + jw->isMapped = True; + // insets: negative values are ignored + int left=-1, right=-1, top=-1, bottom=-1; + if( NewtWindows_updateInsets(dpy, jw, &left, &right, &top, &bottom) ) { + (*env)->CallVoidMethod(env, jw->jwindow, insetsVisibleChangedID, JNI_FALSE, left, right, top, bottom, 1); + } else { + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); } - (*env)->CallVoidMethod(env, jw->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, + DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, isMapped %d -> 0, from_configure %d, child-event: %d\n", + (void*)evt.xunmap.event, (void*)evt.xunmap.window, jw->isMapped, (int)evt.xunmap.from_configure, evt.xunmap.event!=evt.xunmap.window); if( evt.xunmap.event == evt.xunmap.window ) { // ignore child window notification + jw->isMapped = False; (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedID, JNI_FALSE, JNI_FALSE); } break; @@ -693,7 +768,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage /* * Class: Java_jogamp_newt_driver_x11_DisplayDriver * Method: createPointerIcon0 - * Signature: (JJILjava/lang/Object;I)V + * Signature: (JJIZIIII)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_createPointerIcon0 (JNIEnv *env, jclass clazz, jlong display, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY) @@ -731,7 +806,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_createPointerI /* * Class: Java_jogamp_newt_driver_x11_DisplayDriver * Method: destroyPointerIcon0 - * Signature: (JJILjava/lang/Object;I)V + * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_destroyPointerIcon0 (JNIEnv *env, jclass clazz, jlong display, jlong handle) diff --git a/src/newt/native/X11RandR13.c b/src/newt/native/X11RandR13.c index 0dd53feb8..3f9dff289 100644 --- a/src/newt/native/X11RandR13.c +++ b/src/newt/native/X11RandR13.c @@ -39,6 +39,14 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR13_getScreenResources0 Display *dpy = (Display *) (intptr_t) display; Window root = RootWindow(dpy, (int)screen_idx); + /* Bug 1183 + * XRRGetScreenResourcesCurrent (or XRRGetScreenResources) + * _occasionally_ reports empty data + * unless XRRGetScreenSizeRange has been called once. + */ + int minWidth, minHeight, maxWidth, maxHeight; + XRRGetScreenSizeRange ( dpy, root, &minWidth, &minHeight, &maxWidth, &maxHeight); + XRRScreenResources *res = XRRGetScreenResourcesCurrent( dpy, root); // 1.3 // XRRScreenResources *res = XRRGetScreenResources( dpy, root); // 1.2 diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 778b71cc5..de2bddc86 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -85,53 +85,7 @@ static uintptr_t getPtrOut32Long(unsigned long * src) { #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 -#define _MASK_NET_WM_STATE ( 1 << 0 ) -#define _MASK_NET_WM_STATE_MODAL ( 1 << 1 ) -#define _MASK_NET_WM_STATE_STICKY ( 1 << 2 ) -#define _MASK_NET_WM_STATE_MAXIMIZED_VERT ( 1 << 3 ) -#define _MASK_NET_WM_STATE_MAXIMIZED_HORZ ( 1 << 4 ) -#define _MASK_NET_WM_STATE_SHADED ( 1 << 5 ) -#define _MASK_NET_WM_STATE_HIDDEN ( 1 << 8 ) -#define _MASK_NET_WM_STATE_FULLSCREEN ( 1 << 9 ) -#define _MASK_NET_WM_STATE_ABOVE ( 1 << 10 ) -#define _MASK_NET_WM_STATE_BELOW ( 1 << 11 ) -#define _MASK_NET_WM_STATE_DEMANDS_ATTENTION ( 1 << 12 ) -#define _MASK_NET_WM_STATE_FOCUSED ( 1 << 13 ) -#define _MASK_NET_WM_BYPASS_COMPOSITOR ( 1 << 14 ) -#define _MASK_NET_WM_DESKTOP ( 1 << 15 ) -#define _MASK_NET_CURRENT_DESKTOP ( 1 << 16 ) -#define _MASK_NET_WM_WINDOW_TYPE ( 1 << 17 ) -#define _MASK_NET_WM_WINDOW_TYPE_NORMAL ( 1 << 18 ) -#define _MASK_NET_WM_WINDOW_TYPE_POPUP_MENU ( 1 << 19 ) -#define _MASK_NET_FRAME_EXTENTS ( 1 << 20 ) -#define _MASK_NET_SUPPORTED ( 1 << 21 ) -#define _MASK_WM_CHANGE_STATE ( 1 << 22 ) -#define _MASK_MOTIF_WM_HINTS ( 1 << 23 ) - -#define _NET_WM_STATE_IDX 0 -#define _NET_WM_STATE_MODAL_IDX 1 -#define _NET_WM_STATE_STICKY_IDX 2 -#define _NET_WM_STATE_MAXIMIZED_VERT_IDX 3 -#define _NET_WM_STATE_MAXIMIZED_HORZ_IDX 4 -#define _NET_WM_STATE_SHADED_IDX 5 -#define _NET_WM_STATE_SKIP_TASKBAR_IDX 6 -#define _NET_WM_STATE_SKIP_PAGER_IDX 7 -#define _NET_WM_STATE_HIDDEN_IDX 8 -#define _NET_WM_STATE_FULLSCREEN_IDX 9 -#define _NET_WM_STATE_ABOVE_IDX 10 -#define _NET_WM_STATE_BELOW_IDX 11 -#define _NET_WM_STATE_DEMANDS_ATTENTION_IDX 12 -#define _NET_WM_STATE_FOCUSED_IDX 13 -#define _NET_WM_BYPASS_COMPOSITOR_IDX 14 -#define _NET_WM_DESKTOP_IDX 15 -#define _NET_CURRENT_DESKTOP_IDX 16 -#define _NET_WM_WINDOW_TYPE_IDX 17 -#define _NET_WM_WINDOW_TYPE_NORMAL_IDX 18 -#define _NET_WM_WINDOW_TYPE_POPUP_MENU_IDX 19 -#define _NET_FRAME_EXTENTS_IDX 20 -#define _NET_SUPPORTED_IDX 21 -#define _WM_CHANGE_STATE_IDX 22 -#define _MOTIF_WM_HINTS_IDX 23 +/** Sync w/ X11Common.h MASK and IDX */ static const char * _ALL_ATOM_NAMES[] = { /* 0 */ "_NET_WM_STATE", /* 1 */ "_NET_WM_STATE_MODAL", @@ -155,8 +109,9 @@ static const char * _ALL_ATOM_NAMES[] = { /* 19 */ "_NET_WM_WINDOW_TYPE_POPUP_MENU", /* 20 */ "_NET_FRAME_EXTENTS", /* 21 */ "_NET_SUPPORTED", - /* 22 */ "WM_CHANGE_STATE", - /* 23 */ "_MOTIF_WM_HINTS" + /* 22 */ "_NET_ACTIVE_WINDOW", + /* 23 */ "WM_CHANGE_STATE", + /* 24 */ "_MOTIF_WM_HINTS" }; static const uint32_t _ALL_ATOM_COUNT = (uint32_t)(sizeof(_ALL_ATOM_NAMES)/sizeof(const char *)); @@ -178,21 +133,20 @@ static uint32_t NewtWindows_getSupportedFeatureEWMH(Display *dpy, const Atom * a return 0; } static uint32_t NewtWindows_getSupportedFeaturesEWMH(Display *dpy, Window root, Atom * allAtoms, Bool verbose) { - Atom * actions = NULL; + Atom * properties = NULL; Atom type = 0; - unsigned long action_len = 0, remain = 0; + unsigned long props_count = 0, remain = 0; int form = 0, i = 0; uint32_t res = 0; Status s; - XSync(dpy, False); if ( Success == (s = XGetWindowProperty(dpy, root, allAtoms[_NET_SUPPORTED_IDX], 0, 1024, False, AnyPropertyType, - &type, &form, &action_len, &remain, (unsigned char**)&actions)) ) { - if( NULL != actions ) { - for(i=0; i<action_len; i++) { - res |= NewtWindows_getSupportedFeatureEWMH(dpy, allAtoms, actions[i], i, verbose); + &type, &form, &props_count, &remain, (unsigned char**)&properties)) ) { + if( NULL != properties ) { + for(i=0; i<props_count; i++) { + res |= NewtWindows_getSupportedFeatureEWMH(dpy, allAtoms, properties[i], i, verbose); } - XFree(actions); + XFree(properties); } if(verbose) { fprintf(stderr, "**************** X11: Feature EWMH CHECK: 0x%X\n", res); @@ -202,6 +156,39 @@ static uint32_t NewtWindows_getSupportedFeaturesEWMH(Display *dpy, Window root, } return res; } +uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, JavaWindow *w) { + Bool verbose = +#ifdef VERBOSE_ON + True +#else + False +#endif + ; + Window window = w->window; + Atom * allAtoms = w->allAtoms; + Atom * properties = NULL; + Atom type = 0; + unsigned long props_count = 0, remain = 0; + int form = 0, i = 0; + uint32_t res = 0; + Status s; + + if ( Success == (s = XGetWindowProperty(dpy, window, allAtoms[_NET_WM_STATE_IDX], 0, 1024, False, AnyPropertyType, + &type, &form, &props_count, &remain, (unsigned char**)&properties)) ) { + if( NULL != properties ) { + for(i=0; i<props_count; i++) { + res |= NewtWindows_getSupportedFeatureEWMH(dpy, allAtoms, properties[i], i, verbose); + } + XFree(properties); + } + if(verbose) { + fprintf(stderr, "**************** X11: WM_STATE of %p: %d props -> 0x%X\n", (void*)window, (int)props_count, res); + } + } else if(verbose) { + fprintf(stderr, "**************** X11: WM_STATE of %p: XGetWindowProperty failed: %d\n", (void*)window, s); + } + return res; +} static JavaWindow* createJavaWindowProperty(JNIEnv *env, Display *dpy, Window root, Window window, jlong javaObjectAtom, jlong windowDeleteAtom, jobject obj, Bool verbose) { @@ -222,6 +209,9 @@ static JavaWindow* createJavaWindowProperty(JNIEnv *env, Display *dpy, Window ro res->windowDeleteAtom = (Atom)windowDeleteAtom; res->supportedAtoms = NewtWindows_getSupportedFeaturesEWMH(dpy, root, allAtoms, verbose); res->lastDesktop = 0; //undef + res->maxHorz = False; + res->maxVert = False; + res->isMapped = False; } unsigned long jogl_java_object_data[2]; // X11 is based on 'unsigned long' int nitems_32 = putPtrIn32Long( jogl_java_object_data, (uintptr_t) res); @@ -325,7 +315,6 @@ static void NewtWindows_setCWAbove(Display *dpy, Window w) { memset(&xwc, 0, sizeof(XWindowChanges)); xwc.stack_mode = Above; XConfigureWindow(dpy, w, CWStackMode, &xwc); - XSync(dpy, False); } static Status NewtWindows_getWindowPositionRelative2Parent (Display *dpy, Window w, int *x_return, int *y_return) { Window root_return; @@ -413,8 +402,7 @@ static void NewtWindows_setDecorations (Display *dpy, JavaWindow *w, Bool decora #ifdef DECOR_USE_EWMH XChangeProperty( dpy, w->window, w->allAtoms[_NET_WM_WINDOW_TYPE_IDX], XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); #endif - - XSync(dpy, False); + XFlush(dpy); } static Bool NewtWindows_hasDecorations (Display *dpy, JavaWindow * w) { @@ -446,7 +434,6 @@ static void NewtWindows_requestFocus (Display *dpy, JavaWindow * jw, Bool force) Window focus_return; int revert_to_return; - XSync(dpy, False); XGetInputFocus(dpy, &focus_return, &revert_to_return); DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d, hasFocus %d\n", dpy, (void*)jw->window, force, focus_return==jw->window); @@ -461,16 +448,14 @@ static void NewtWindows_requestFocus (Display *dpy, JavaWindow * jw, Bool force) XSetInputFocus(dpy, jw->window, RevertToParent, CurrentTime); } } + XFlush(dpy); DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d - FIN\n", dpy, (void*)jw->window, force); - XSync(dpy, False); } -Status NewtWindows_updateInsets(JNIEnv *env, Display *dpy, JavaWindow * w, int *left, int *right, int *top, int *bottom) { +Bool NewtWindows_updateInsets(Display *dpy, JavaWindow * w, int *left, int *right, int *top, int *bottom) { if(0 != NewtWindows_getFrameExtends(dpy, w, 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); - (*env)->CallVoidMethod(env, w->jwindow, insetsChangedID, JNI_FALSE, *left, *right, *top, *bottom); - return 1; // OK + DBG_PRINT( "NewtWindows_updateInsets: insets by _NET_FRAME_EXTENTS [ l %d, r %d, t %d, b %d ]\n", *left, *right, *top, *bottom); + return True; // OK } Bool hasDecor = NewtWindows_hasDecorations (dpy, w); @@ -480,43 +465,23 @@ Status NewtWindows_updateInsets(JNIEnv *env, Display *dpy, JavaWindow * w, int * Window parent = NewtWindows_getParent(dpy, w->window); if(0 != NewtWindows_getWindowPositionRelative2Parent (dpy, parent, left, top)) { *right = *left; *bottom = *top; - DBG_PRINT( "NewtWindows_updateInsets: insets by parent position [ l %d, r %d, t %d, b %d ]\n", - *left, *right, *top, *bottom); - (*env)->CallVoidMethod(env, w->jwindow, insetsChangedID, JNI_FALSE, *left, *right, *top, *bottom); - return 1; // OK + DBG_PRINT( "NewtWindows_updateInsets: insets by parent position [ l %d, r %d, t %d, b %d ]\n", *left, *right, *top, *bottom); + return True; // OK } } DBG_PRINT( "NewtWindows_updateInsets: cannot determine insets - hasDecor %d\n", hasDecor); - return 0; // Error + return False; // Error } -void NewtWindows_updateMinMaxSize(JNIEnv *env, Display *dpy, JavaWindow * w) { - XSizeHints * xsh = XAllocSizeHints(); - long xsh_bits = 0; - int min_width=-1, min_height=-1; - int max_width=-1, max_height=-1; - if( NULL != xsh ) { - xsh->flags = 0; - xsh->min_width=0; - xsh->min_height=0; - xsh->max_width=0; - xsh->max_height=0; - if( 0 != XGetWMNormalHints(dpy, w->window, xsh, &xsh_bits) ) { - // OK - if( 0 != ( xsh_bits & PMinSize ) ) { - min_width = xsh->min_width; - min_height = xsh->min_height; - } - if( 0 != ( xsh_bits & PMaxSize ) ) { - max_width = xsh->max_width; - max_height = xsh->max_height; - } - DBG_PRINT( "NewtWindows_updateMinMaxSize: XGetWMNormalHints 0x%X / 0x%X for window %p on display %p\n", xsh_bits, xsh->flags, (void*)w->window, dpy); - (*env)->CallVoidMethod(env, w->jwindow, minMaxSizeChangedID, min_width, min_height, max_width, max_height); - } else { - DBG_PRINT( "NewtWindows_updateMinMaxSize: XGetWMNormalHints failed (0x%X / 0x%X) for window %p on display %p\n", xsh_bits, xsh->flags, (void*)w->window, dpy); - } - XFree(xsh); +Bool NewtWindows_updateMaximized(Display *dpy, JavaWindow * w, uint32_t netWMState) { + Bool maxHorz = 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_HORZ & netWMState ) ; + Bool maxVert = 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_VERT & netWMState ) ; + if( w->maxHorz != maxHorz || w->maxVert != maxVert ) { + w->maxHorz = maxHorz; + w->maxVert = maxVert; + return True; + } else { + return False; } } @@ -546,11 +511,20 @@ static void NewtWindows_setWindowTypeEWMH (Display *dpy, JavaWindow * w, int typ } // else { } if( 0 != types[0] ) { XChangeProperty( dpy, w->window, w->allAtoms[_NET_WM_WINDOW_TYPE_IDX], XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1); - XSync(dpy, False); + XFlush(dpy); + } +} + +void NewtWindows_setUrgency(Display *dpy, Window window, Bool enable) { + XWMHints wmh; + memset ( &wmh, 0, sizeof(wmh) ); + if( enable ) { + wmh.flags = XUrgencyHint; } + XSetWMHints(dpy, window, &wmh); } -static void NewtWindows_sendNET_WM_STATE(Display *dpy, Window root, JavaWindow *w, int prop1Idx, int prop2Idx, Bool enable) { +void NewtWindows_sendNET_WM_STATE(Display *dpy, Window root, JavaWindow *w, int prop1Idx, int prop2Idx, Bool enable) { XEvent xev; int i=0; @@ -671,12 +645,18 @@ static void NewtWindows_setStackingEWMHFlags (Display *dpy, Window root, JavaWin XChangeProperty( dpy, w->window, w->allAtoms[_NET_WM_BYPASS_COMPOSITOR_IDX], XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&value, 1); } } else if( changeMaxVert || changeMaxHorz ) { + if( changeMaxHorz ) { + w->maxHorz = enable; + } + if( changeMaxVert ) { + w->maxVert = enable; + } NewtWindows_sendNET_WM_STATE(dpy, root, w, - changeMaxVert ? _NET_WM_STATE_MAXIMIZED_VERT_IDX : 0, changeMaxHorz ? _NET_WM_STATE_MAXIMIZED_HORZ_IDX : 0, + changeMaxVert ? _NET_WM_STATE_MAXIMIZED_VERT_IDX : 0, enable); } - XSync(dpy, False); + XFlush(dpy); DBG_PRINT( "X11: setStackingEWMHFlags ON %d, change[Sticky %d, Fullscreen %d, Above %d, Below %d, MaxV %d, MaxH %d]\n", enable, changeSticky, changeFullscreen, changeAbove, changeBelow, changeMaxVert, changeMaxHorz); } @@ -691,35 +671,47 @@ static Bool WaitForUnmapNotify( Display *dpy, XEvent *event, XPointer arg ) { static void NewtWindows_setVisible(Display *dpy, Window root, JavaWindow* jw, Bool visible, Bool useWM, Bool waitForNotify) { XEvent event; - if( !visible && useWM && 0 != ( _MASK_NET_WM_STATE_HIDDEN & jw->supportedAtoms ) ) { - DBG_PRINT( "X11: setVisible -> %d, method: IconicState, wait %d, window %p\n", (int)visible, (int)waitForNotify, (void*)jw->window); - // It has been experienced that UnmapNotify is not sent for child windows when using IconicState! + DBG_PRINT( "X11: setVisible -> %d, useWM: %d, wait %d, window %p\n", (int)visible, (int)useWM, (int)waitForNotify, (void*)jw->window); + if( useWM && jw->isMapped && 0 != ( _MASK_NET_WM_STATE_HIDDEN & jw->supportedAtoms ) ) { + // It has been experienced that MapNotify/UnmapNotify is not sent for windows when using NormalState/IconicState! + // See X11Display.c::Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0 case ConfigureNotify + // NewtWindows_sendNET_WM_STATE(dpy, root, jw, _NET_WM_STATE_DEMANDS_ATTENTION_IDX, 0, True); + // NewtWindows_setUrgency(dpy, jw->window, True); XEvent xev; memset ( &xev, 0, sizeof(xev) ); - xev.type = ClientMessage; - xev.xclient.window = jw->window; - xev.xclient.message_type = jw->allAtoms[_WM_CHANGE_STATE_IDX]; - xev.xclient.format = 32; - xev.xclient.data.l[0] = IconicState; - XSendEvent ( dpy, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xev ); - // NewtWindows_sendNET_WM_STATE(dpy, root, jw, _NET_WM_STATE_HIDDEN_IDX, 0, !visible); - if(waitForNotify) { - XIfEvent( dpy, &event, WaitForUnmapNotify, (XPointer) jw->window ); + if( visible ) { + // NormalState does not work on some WMs (Gnome, KDE) + xev.type = ClientMessage; + xev.xclient.window = jw->window; + xev.xclient.message_type = jw->allAtoms[_NET_ACTIVE_WINDOW_IDX]; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; //source indication for normal applications + xev.xclient.data.l[1] = CurrentTime; + XSendEvent ( dpy, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xev ); + } else { + xev.type = ClientMessage; + xev.xclient.window = jw->window; + xev.xclient.message_type = jw->allAtoms[_WM_CHANGE_STATE_IDX]; + xev.xclient.format = 32; + xev.xclient.data.l[0] = IconicState; + XSendEvent ( dpy, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xev ); } } else { - DBG_PRINT( "X11: setVisible -> %d, method: Map/Unmap, wait %d, window %p\n", (int)visible, (int)waitForNotify, (void*)jw->window); if( visible ) { XMapRaised(dpy, jw->window); if(waitForNotify) { XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) jw->window ); } + jw->isMapped=True; } else { XUnmapWindow(dpy, jw->window); if(waitForNotify) { XIfEvent( dpy, &event, WaitForUnmapNotify, (XPointer) jw->window ); } + jw->isMapped=False; } } + XFlush(dpy); } @@ -753,7 +745,7 @@ static void NewtWindows_setPosSize(Display *dpy, JavaWindow* w, jint x, jint y, xwc.height=height; } XConfigureWindow(dpy, w->window, flags, &xwc); - XSync(dpy, False); + XFlush(dpy); } } @@ -840,24 +832,23 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind pVisualQuery=NULL; } - attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap | - CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask ) ; + attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | + CWBackPixmap | CWBackPixel | CWBorderPixel | CWColormap | + CWOverrideRedirect | CWEventMask ) ; memset(&xswa, 0, sizeof(xswa)); - xswa.override_redirect = False; // use the window manager, always (default) - xswa.border_pixel = 0; - xswa.background_pixmap = None; xswa.backing_store=NotUseful; /* NotUseful, WhenMapped, Always */ xswa.backing_planes=0; /* planes to be preserved if possible */ xswa.backing_pixel=0; /* value to use in restoring planes */ + xswa.background_pixmap = None; + xswa.background_pixel = BlackPixel(dpy, scrn_idx); + xswa.border_pixel = 0; + xswa.colormap = XCreateColormap(dpy, windowParent, visual, AllocNone); + xswa.override_redirect = False; // use the window manager, always (default) xswa.event_mask = X11_MOUSE_EVENT_MASK; xswa.event_mask |= KeyPressMask | KeyReleaseMask ; - xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ; - - xswa.colormap = XCreateColormap(dpy, - windowParent, - visual, - AllocNone); + xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask; + // xswa.event_mask |= VisibilityChangeMask; { int _x = x, _y = y; // pos for CreateWindow, might be tweaked @@ -882,6 +873,7 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind NewtCommon_throwNewRuntimeException(env, "could not create Window, bail out!"); return 0; } + // XClearWindow(dpy, window); XSetWMProtocols(dpy, window, &wm_delete_atom, 1); // windowDeleteAtom javaWindow = createJavaWindowProperty(env, dpy, root, window, javaObjectAtom, windowDeleteAtom, obj, verbose); @@ -893,7 +885,8 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind // we can pre-map the window here to be able to gather the insets and position. { XEvent event; - int left=0, right=0, top=0, bottom=0; + // insets: negative values are ignored + int left=-1, right=-1, top=-1, bottom=-1; const unsigned char * pixelPtr = NULL; // NOTE: MUST BE DIRECT BUFFER, since _NET_WM_ICON Atom uses buffer directly! @@ -908,16 +901,20 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind XMapWindow(dpy, window); XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) window ); // wait to get proper insets values - - XSync(dpy, False); + javaWindow->isMapped=True; if( JNI_FALSE == pixels_is_direct && NULL != pixelPtr ) { (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); } // send insets before visibility, allowing java code a proper sync point! - NewtWindows_updateInsets(env, dpy, javaWindow, &left, &right, &top, &bottom); - (*env)->CallVoidMethod(env, javaWindow->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); + XSync(dpy, False); + if( NewtWindows_updateInsets(dpy, javaWindow, &left, &right, &top, &bottom) ) { + (*env)->CallVoidMethod(env, javaWindow->jwindow, insetsVisibleChangedID, JNI_FALSE, left, right, top, bottom, 1); + } else { + (*env)->CallVoidMethod(env, javaWindow->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); + left=0; right=0; top=0; bottom=0; + } if( TST_FLAG_IS_AUTOPOSITION(flags) ) { // get position from WM @@ -955,6 +952,7 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind NewtWindows_setMinMaxSize(dpy, javaWindow, width, height, width, height); } } + XFlush(dpy); handles[0] = (jlong)(intptr_t)window; handles[1] = (jlong)(intptr_t)javaWindow; jhandles = (*env)->NewLongArray(env, 2); @@ -968,6 +966,34 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind /* * Class: jogamp_newt_driver_x11_WindowDriver + * Method: GetSupportedReconfigMask0 + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_WindowDriver_GetSupportedReconfigMask0 + (JNIEnv *env, jclass clazz, jlong javaWindow) +{ + JavaWindow * jw = (JavaWindow*)(intptr_t)javaWindow; + uint32_t supported = jw->supportedAtoms; + return + FLAG_IS_VISIBLE | + FLAG_IS_AUTOPOSITION | + FLAG_IS_CHILD | + FLAG_IS_FOCUSED | + FLAG_IS_UNDECORATED | + ( ( 0 != ( _MASK_NET_WM_STATE_ABOVE & supported ) ) ? FLAG_IS_ALWAYSONTOP : 0 ) | + ( ( 0 != ( _MASK_NET_WM_STATE_BELOW & supported ) ) ? FLAG_IS_ALWAYSONBOTTOM : 0 ) | + ( ( 0 != ( _MASK_NET_WM_DESKTOP & supported ) ) ? FLAG_IS_STICKY : 0 ) | + FLAG_IS_RESIZABLE | + ( ( 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_VERT & supported ) ) ? FLAG_IS_MAXIMIZED_VERT : 0 ) | + ( ( 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_HORZ & supported ) ) ? FLAG_IS_MAXIMIZED_HORZ : 0 ) | + FLAG_IS_FULLSCREEN | + FLAG_IS_POINTERVISIBLE | + FLAG_IS_POINTERCONFINED | + FLAG_IS_FULLSCREEN_SPAN; +} + +/* + * Class: jogamp_newt_driver_x11_WindowDriver * Method: CloseWindow * Signature: (JJ)V */ @@ -1006,6 +1032,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 XGetWindowAttributes(dpy, jw->window, &xwa); // prefetch colormap to be destroyed after window destruction XSelectInput(dpy, jw->window, 0); XUnmapWindow(dpy, jw->window); + jw->isMapped=False; // Drain all events related to this window .. Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, @@ -1045,7 +1072,7 @@ static Bool WaitForReparentNotify( Display *dpy, XEvent *event, XPointer arg ) { * Signature: (JIJJIIIII)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindow0 - (JNIEnv *env, jobject obj, jlong jdisplay, jint screen_index, + (JNIEnv *env, jclass clazz, jlong jdisplay, jint screen_index, jlong jparent, jlong javaWindow, jint x, jint y, jint width, jint height, jint flags) { @@ -1101,6 +1128,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo TST_FLAG_CHANGE_STICKY(flags), TST_FLAG_IS_STICKY(flags), fsEWMHFlags); + XSync(dpy, False); + // FS Note: To toggle FS, utilizing the _NET_WM_STATE_FULLSCREEN WM state should be enough. // However, we have to consider other cases like reparenting and WM which don't support it. #if 0 // Also doesn't work work properly w/ Unity WM @@ -1142,8 +1171,9 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo XReparentWindow( dpy, jw->window, parent, x, y ); // actual reparent call #ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) jw->window ); + #else + XSync(dpy, False); #endif - XSync(dpy, False); XSetWMProtocols(dpy, jw->window, &wm_delete_atom, 1); // windowDeleteAtom // Fix for Unity WM, i.e. _remove_ persistent previous states NewtWindows_setStackingEWMHFlags(dpy, root, jw, fsEWMHFlags, False); @@ -1185,10 +1215,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo // CHILD: out -> in DBG_PRINT( "X11: reconfigureWindow0 PARENTING out->in\n"); XReparentWindow( dpy, jw->window, parent, x, y ); // actual reparent call + XFlush(dpy); #ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) jw->window ); + #else + XSync(dpy, False); #endif - XSync(dpy, False); } if( tempInvisible ) { @@ -1200,7 +1232,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo if( TST_FLAG_IS_VISIBLE(flags) ) { DBG_PRINT( "X11: reconfigureWindow0 VISIBLE ON\n"); NewtWindows_setVisible(dpy, root, jw, True /* visible */, useWM, False /* wait */); - XSync(dpy, False); if( !TST_FLAG_IS_MAXIMIZED_ANY(flags) ) { // WM may disregard pos/size XConfigureWindow requests for invisible windows! DBG_PRINT( "X11: reconfigureWindow0 setPosSize.2 %d/%d %dx%d\n", x, y, width, height); @@ -1209,7 +1240,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo } else { DBG_PRINT( "X11: reconfigureWindow0 VISIBLE OFF\n"); NewtWindows_setVisible(dpy, root, jw, False /* visible */, useWM, False /* wait */); - XSync(dpy, False); } } @@ -1230,6 +1260,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo NewtWindows_setMinMaxSize(dpy, jw, -1, -1, -1, -1); // FIXME: .. } } + XFlush(dpy); DBG_PRINT( "X11: reconfigureWindow0 X (full)\n"); } @@ -1239,9 +1270,11 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo * Signature: (JJZ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_requestFocus0 - (JNIEnv *env, jobject obj, jlong display, jlong javaWindow, jboolean force) + (JNIEnv *env, jclass clazz, jlong display, jlong javaWindow, jboolean force) { - NewtWindows_requestFocus ( (Display *) (intptr_t) display, (JavaWindow*)(intptr_t)javaWindow, JNI_TRUE==force?True:False ) ; + Display * dpy = (Display *) (intptr_t) display; + XSync(dpy, False); + NewtWindows_requestFocus ( dpy, (JavaWindow*)(intptr_t)javaWindow, JNI_TRUE==force?True:False ) ; } /* diff --git a/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java b/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java index 86041b35d..cd79409e5 100644 --- a/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java +++ b/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java @@ -85,6 +85,16 @@ import java.util.*; } @Override + public final boolean searchToolLibInSystemPath() { + return true; + } + + @Override + public final boolean searchToolLibSystemPathFirst() { + return true; + } + + @Override public final List<List<String>> getToolLibNames() { return new ArrayList<List<String>>(); // None } diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java index e4fabbbcc..eff2aae49 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java @@ -36,6 +36,7 @@ import com.jogamp.opengl.GLProfile; import jogamp.newt.driver.android.NewtBaseActivity; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.event.MonitorEvent; import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; @@ -90,7 +91,7 @@ public class NEWTGearsES2Activity extends NewtBaseActivity { public void mousePressed(final MouseEvent e) { if( e.getPointerCount() == 3 ) { Log.d(TAG, "MemoryHog"); - new Thread(new Runnable() { + new InterruptSource.Thread(null, new Runnable() { public void run() { final ArrayList<Buffer> buffers = new ArrayList<Buffer>(); while(true) { diff --git a/src/test/com/jogamp/opengl/test/bugs/Bug735Inv0AppletAWT.java b/src/test/com/jogamp/opengl/test/bugs/Bug735Inv0AppletAWT.java index 89d28c08d..7430dcd38 100644 --- a/src/test/com/jogamp/opengl/test/bugs/Bug735Inv0AppletAWT.java +++ b/src/test/com/jogamp/opengl/test/bugs/Bug735Inv0AppletAWT.java @@ -27,7 +27,7 @@ import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.GLUniformData; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.glu.GLU; - +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.LandscapeES2; @@ -98,7 +98,7 @@ public class Bug735Inv0AppletAWT extends Applet implements Runnable { } public void start() { - thread = new Thread(this, "Animation Thread"); + thread = new InterruptSource.Thread(null, this, "Animation Thread"); thread.start(); } diff --git a/src/test/com/jogamp/opengl/test/bugs/Bug735Inv1AppletAWT.java b/src/test/com/jogamp/opengl/test/bugs/Bug735Inv1AppletAWT.java index 5019391ad..b31a5f410 100644 --- a/src/test/com/jogamp/opengl/test/bugs/Bug735Inv1AppletAWT.java +++ b/src/test/com/jogamp/opengl/test/bugs/Bug735Inv1AppletAWT.java @@ -27,7 +27,7 @@ import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.GLUniformData; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.glu.GLU; - +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.LandscapeES2; @@ -100,7 +100,7 @@ public class Bug735Inv1AppletAWT extends Applet implements Runnable { } public void start() { - thread = new Thread(this, "Animation Thread"); + thread = new InterruptSource.Thread(null, this, "Animation Thread"); thread.start(); } diff --git a/src/test/com/jogamp/opengl/test/bugs/Bug735Inv2AppletAWT.java b/src/test/com/jogamp/opengl/test/bugs/Bug735Inv2AppletAWT.java index 1228f1453..d0e4448cc 100644 --- a/src/test/com/jogamp/opengl/test/bugs/Bug735Inv2AppletAWT.java +++ b/src/test/com/jogamp/opengl/test/bugs/Bug735Inv2AppletAWT.java @@ -20,7 +20,8 @@ import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.awt.GLCanvas; - +import com.jogamp.common.util.InterruptSource; +import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.LandscapeES2; @@ -82,7 +83,7 @@ public class Bug735Inv2AppletAWT extends Applet implements Runnable { public void start() { initDraw(); - thread = new Thread(this, "Animation Thread"); + thread = new InterruptSource.Thread(null, this, "Animation Thread"); thread.start(); } @@ -219,7 +220,7 @@ public class Bug735Inv2AppletAWT extends Applet implements Runnable { System.err.println("swapInterval "+SWAP_INTERVAL); System.err.println("exclusiveContext "+USE_ECT); if(waitForKey) { - UITestCase.waitForKey("Start"); + JunitTracer.waitForKey("Start"); } final GraphicsEnvironment environment = diff --git a/src/test/com/jogamp/opengl/test/bugs/Issue344Base.java b/src/test/com/jogamp/opengl/test/bugs/Issue344Base.java index 184a2ef0f..7532ca6db 100644 --- a/src/test/com/jogamp/opengl/test/bugs/Issue344Base.java +++ b/src/test/com/jogamp/opengl/test/bugs/Issue344Base.java @@ -6,6 +6,7 @@ import java.awt.Frame; import java.awt.event.*; import java.awt.geom.*; +import com.jogamp.common.util.InterruptSource; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; @@ -49,7 +50,7 @@ public abstract class Issue344Base implements GLEventListener frame.setSize(512, 512); frame.addWindowListener(new WindowAdapter() { public void windowClosing(final WindowEvent e) { - new Thread(new Runnable() { + new InterruptSource.Thread(null, new Runnable() { public void run() { System.exit(0); } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/FontSet01.java b/src/test/com/jogamp/opengl/test/junit/graph/FontSet01.java index 0666ec4db..38eda9adf 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/FontSet01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/FontSet01.java @@ -14,22 +14,22 @@ public class FontSet01 { fonts[i++] = FontFactory.get(FontFactory.UBUNTU).getDefault(); // FontSet.FAMILY_REGULAR, FontSet.STYLE_NONE fonts[i++] = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_REGULAR, FontSet.STYLE_ITALIC); fonts[i++] = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_REGULAR, FontSet.STYLE_BOLD); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeMono.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeMonoBold.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeSans.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeSansBold.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeSerif.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeSerifBold.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeSerifBoldItalic.ttf").getInputStream(), true); - fonts[i++] = FontFactory.get(IOUtil.getResource(TestTextRendererNEWTBugXXXX.class, - "fonts/freefont/FreeSerifItalic.ttf").getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMono.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMonoBold.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSans.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSansBold.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerif.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerifBold.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerifBoldItalic.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerifItalic.ttf", + TestTextRendererNEWTBugXXXX.class.getClassLoader(), TestTextRendererNEWTBugXXXX.class).getInputStream(), true); return fonts; } } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java index 86b129fe1..36e263f78 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java @@ -54,6 +54,7 @@ import com.jogamp.graph.curve.opengl.RenderState; import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontFactory; import com.jogamp.graph.geom.SVertex; +import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.Window; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.MiscUtils; @@ -73,7 +74,7 @@ public class TestTextRendererNEWT00 extends UITestCase { static int GraphVBAASamples = 0; static int GraphMSAASamples = 0; static boolean ManualTest = false; - static int SwapInterval = 0; + static int SwapInterval = 1; static String fontFileName = null; static URL fontURL = null; @@ -213,7 +214,7 @@ public class TestTextRendererNEWT00 extends UITestCase { window.display(); System.err.println("Chosen: "+window.getChosenGLCapabilities()); if( WaitStartEnd ) { - UITestCase.waitForKey("Start"); + JunitTracer.waitForKey("Start"); } final RenderState rs = RenderState.createRenderState(SVertex.factory()); @@ -252,7 +253,7 @@ public class TestTextRendererNEWT00 extends UITestCase { }); anim.stop(); if( WaitStartEnd ) { - UITestCase.waitForKey("Stop"); + JunitTracer.waitForKey("Stop"); } destroyWindow(window); } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java index 4e66f6920..37d457057 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java @@ -102,7 +102,7 @@ public class TestTextRendererNEWT10 extends UITestCase { forceGL3 = true; } else if(args[i].equals("-font")) { i++; - font = FontFactory.get(IOUtil.getResource(TestTextRendererNEWT10.class, args[i]).getInputStream(), true); + font = FontFactory.get(IOUtil.getResource(args[i], TestTextRendererNEWT10.class.getClassLoader(), TestTextRendererNEWT10.class).getInputStream(), true); } else if(args[i].equals("-fontSize")) { i++; fontSize = MiscUtils.atof(args[i], fontSize); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java index 73b76debb..2d3b0664e 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java @@ -47,6 +47,7 @@ import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.newt.Window; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.opengl.GLWindow; @@ -121,6 +122,17 @@ public abstract class GPURendererListenerBase01 implements GLEventListener { @Override public void init(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + final Window window = (Window) upObj; + final float[] sDPI = window.getPixelsPerMM(new float[2]); + sDPI[0] *= 25.4f; + sDPI[1] *= 25.4f; + System.err.println("DPI "+sDPI[0]+" x "+sDPI[1]); + + final float[] hasSurfacePixelScale1 = window.getCurrentSurfaceScale(new float[2]); + System.err.println("HiDPI PixelScale: "+hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); + } autoDrawable = drawable; GL2ES2 gl = drawable.getGL().getGL2ES2(); if(debug) { @@ -302,9 +314,16 @@ public abstract class GPURendererListenerBase01 implements GLEventListener { @Override public boolean run(final GLAutoDrawable drawable) { final GL gl = drawable.getGL(); - int i = gl.getSwapInterval(); - i = i==0 ? 1 : 0; + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = -1; break; + case -1: i = 1; break; + case 1: i = 0; break; + default: i = 1; break; + } gl.setSwapInterval(i); + final GLAnimatorControl a = drawable.getAnimator(); if( null != a ) { a.resetFPSCounter(); @@ -312,7 +331,7 @@ public abstract class GPURendererListenerBase01 implements GLEventListener { if(drawable instanceof FPSCounter) { ((FPSCounter)drawable).resetFPSCounter(); } - System.err.println("Swap Interval: "+i); + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); return true; } }); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java index f7e779cd3..bf0a907b0 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java @@ -34,7 +34,6 @@ import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.RenderState; -import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.geom.SVertex; import com.jogamp.newt.opengl.GLWindow; diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java index c648708d4..945204052 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java @@ -165,9 +165,14 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB super.init(drawable); final Object upObj = drawable.getUpstreamWidget(); if( upObj instanceof Window ) { - final float[] pixelsPerMM = new float[2]; - ((Window)upObj).getPixelsPerMM(pixelsPerMM); - dpiH = pixelsPerMM[1]*25.4f; + final Window window = (Window) upObj; + final float[] sDPI = window.getPixelsPerMM(new float[2]); + sDPI[0] *= 25.4f; + sDPI[1] *= 25.4f; + dpiH = sDPI[1]; + System.err.println("Using screen DPI of "+dpiH); + } else { + System.err.println("Using default DPI of "+dpiH); } fontNameBox = font.getMetricBounds(fontName, font.getPixelSize(fontSizeFName, dpiH)); switchHeadBox(); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java index 4bb72bbd2..33b7e2787 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java @@ -16,6 +16,7 @@ import com.jogamp.opengl.GLPipelineFactory; import com.jogamp.opengl.GLRunnable; import com.jogamp.common.net.Uri; +import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.curve.opengl.RenderState; @@ -354,7 +355,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - new Thread() { + new InterruptSource.Thread() { public void run() { if( null != cDrawable ) { final GLAnimatorControl actrl = cDrawable.getAnimator(); @@ -521,6 +522,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { mPlayer.setTextureUnit(texUnitMediaPlayer); final MediaPlayerButton mPlayerButton = new MediaPlayerButton(renderer.getRenderState().getVertexFactory(), renderModes, button2XSize, button2YSize, mPlayer); + mPlayerButton.setVerbose(true); mPlayerButton.addDefaultEventListener(); mPlayerButton.translate(xStartRight, yStartTop - diffY*1, 0f); mPlayerButton.setToggleable(true); @@ -665,14 +667,17 @@ public class GPUUISceneGLListener0A implements GLEventListener { if( upObj instanceof Window ) { final Window upWin = (Window)upObj; final MonitorDevice mm = upWin.getMainMonitor(); - final float[] monitorPixelsPerMM = mm.getPixelsPerMM(new float[2]); - final float monitorDpiH = monitorPixelsPerMM[1]*25.4f; - final float[] surfacePixelsPerMM = upWin.getPixelsPerMM(new float[2]); - dpiH = surfacePixelsPerMM[1]*25.4f; + final float[] monitorDPI = mm.getPixelsPerMM(new float[2]); + monitorDPI[0] *= 25.4f; + monitorDPI[1] *= 25.4f; + final float[] sDPI = upWin.getPixelsPerMM(new float[2]); + sDPI[0] *= 25.4f; + sDPI[1] *= 25.4f; + dpiH = sDPI[1]; System.err.println("Monitor detected: "+mm); - System.err.println("Monitor dpi: "+monitorDpiH); + System.err.println("Monitor dpi: "+monitorDPI[0]+" x "+monitorDPI[1]); System.err.println("Surface scale: native "+Arrays.toString(upWin.getMaximumSurfaceScale(new float[2]))+", current "+Arrays.toString(upWin.getCurrentSurfaceScale(new float[2]))); - System.err.println("Surface dpi: "+dpiH); + System.err.println("Surface dpi "+sDPI[0]+" x "+sDPI[1]); } else { System.err.println("Using default DPI of "+dpiH); } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java index 8b5b70239..721fe9cb0 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java @@ -180,10 +180,6 @@ public class GPUUISceneNewtCanvasAWTDemo { frame.setVisible(true); } }); - final float[] hasSurfacePixelScale1 = window.getCurrentSurfaceScale(new float[2]); - System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+ - valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ - hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); animator.start(); } } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java index aa6dd00cc..3053ed40a 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java @@ -145,10 +145,6 @@ public class GPUUISceneNewtDemo { }); window.setVisible(true); - final float[] hasSurfacePixelScale1 = window.getCurrentSurfaceScale(new float[2]); - System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+ - valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ - hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); animator.start(); } } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/MediaPlayerButton.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/MediaPlayerButton.java index bdde61ad9..44e2c6034 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/MediaPlayerButton.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/MediaPlayerButton.java @@ -28,7 +28,7 @@ package com.jogamp.opengl.test.junit.graph.demos.ui; import com.jogamp.opengl.GL2ES2; - +import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.geom.Vertex.Factory; @@ -41,7 +41,7 @@ import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; * GPU based resolution independent {@link GLMediaPlayer} Button impl */ public class MediaPlayerButton extends TextureSeqButton { - public boolean verbose = false; + private boolean verbose = false; /** * @param factory @@ -62,6 +62,8 @@ public class MediaPlayerButton extends TextureSeqButton { setEnabled(false); // data and shader n/a yet } + public void setVerbose(final boolean v) { verbose = v; } + /** * Add the default {@link GLMediaEventListener} to {@link #getGLMediaPlayer() this class's GLMediaPlayer}. */ @@ -91,7 +93,7 @@ public class MediaPlayerButton extends TextureSeqButton { // FIXME: mPlayer.resetGLState(); } if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { - new Thread() { + new InterruptSource.Thread() { public void run() { // loop for-ever .. mPlayer.seek(0); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java index 2e3d2fac3..ab5bfb926 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import com.jogamp.opengl.FPSCounter; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLAnimatorControl; @@ -285,16 +286,27 @@ public abstract class UIListenerBase01 implements GLEventListener { else if(arg0.getKeyCode() == KeyEvent.VK_V) { if(null != autoDrawable) { autoDrawable.invoke(false, new GLRunnable() { + @Override public boolean run(final GLAutoDrawable drawable) { final GL gl = drawable.getGL(); - int i = gl.getSwapInterval(); - i = i==0 ? 1 : 0; + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = 1; break; + case 1: i = -1; break; + case -1: i = 0; break; + default: i = 1; break; + } gl.setSwapInterval(i); + final GLAnimatorControl a = drawable.getAnimator(); if( null != a ) { a.resetFPSCounter(); } - System.err.println("Swap Interval: "+i); + if(drawable instanceof FPSCounter) { + ((FPSCounter)drawable).resetFPSCounter(); + } + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); return true; } }); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/GLProfile0XBase.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/GLProfile0XBase.java index 7fd3488ba..75d588f8e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/GLProfile0XBase.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/GLProfile0XBase.java @@ -43,6 +43,7 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; @@ -915,7 +916,7 @@ public abstract class GLProfile0XBase extends UITestCase { Thread.sleep(100); // Same definition as in GLProfile for 'disableOpenGLARBContext' final boolean isOSX = Platform.OSType.MACOS == Platform.getOSType(); - final boolean disableOpenGLARBContext = null != System.getProperty("jogl.disable.openglarbcontext") && !isOSX; + final boolean disableOpenGLARBContext = PropertyAccess.isPropertyDefined("jogl.disable.openglarbcontext", true) && !isOSX; if( disableOpenGLARBContext ) { Assert.assertFalse("Property 'jogl.disable.openglarbcontext' set, but created w/ ARB", glad.getContext().isCreatedWithARBMethod()); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java index 3379129dd..7a5b49168 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/InitConcurrentBaseNEWT.java @@ -28,6 +28,8 @@ package com.jogamp.opengl.test.junit.jogl.acore; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.nativewindow.Capabilities; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.opengl.GLCapabilities; @@ -194,11 +196,11 @@ public abstract class InitConcurrentBaseNEWT extends UITestCase { final String currentThreadName = Thread.currentThread().getName(); final Object syncDone = new Object(); final JOGLTask[] tasks = new JOGLTask[num]; - final Thread[] threads = new Thread[num]; + final InterruptSource.Thread[] threads = new InterruptSource.Thread[num]; int i; for(i=0; i<num; i++) { tasks[i] = new JOGLTask(syncDone, i, reuse); - threads[i] = new Thread(tasks[i], currentThreadName+"-jt"+i); + threads[i] = new InterruptSource.Thread(null, tasks[i], currentThreadName+"-jt"+i); } final long t0 = System.currentTimeMillis(); @@ -211,7 +213,7 @@ public abstract class InitConcurrentBaseNEWT extends UITestCase { try { syncDone.wait(500); } catch (final InterruptedException e) { - throw new RuntimeException(e); + throw new InterruptedRuntimeException(e); } System.err.println(i+": "+doneDump(tasks)); i++; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug1146GLContextDialogToolTipAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug1146GLContextDialogToolTipAWT.java index 42646c07e..a736a481a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug1146GLContextDialogToolTipAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug1146GLContextDialogToolTipAWT.java @@ -52,6 +52,7 @@ import org.junit.Test; import org.junit.runners.MethodSorters; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLProfile; @@ -127,7 +128,7 @@ public class TestBug1146GLContextDialogToolTipAWT extends UITestCase { final String cancelButtonText = UIManager.getString("FileChooser.cancelButtonText",l); // launch robot action .. - new Thread() + new InterruptSource.Thread() { public void run() { @@ -161,7 +162,7 @@ public class TestBug1146GLContextDialogToolTipAWT extends UITestCase { // hover to 'approve' -> tool tip if( null != approveButtonPos ) { AWTRobotUtil.mouseMove(robot, approveButtonPos, MOVE_ITER, MOVE_DELAY); - Thread.sleep(TOOLTIP_WAIT); + java.lang.Thread.sleep(TOOLTIP_WAIT); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java index fd012e86f..a034f9c8a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOAutoDrawableDeadlockAWT.java @@ -44,6 +44,7 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.RunnableTask; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -83,7 +84,7 @@ public class TestFBOAutoDrawableDeadlockAWT extends UITestCase { 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(); + new InterruptSource.Thread(null, rTask, Thread.currentThread().getName()+"-Pbuffer_Creation").start(); try { System.err.println("BB.2"); rTask.getSyncObject().wait(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java index f2e8b86af..d8900b44e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOMix2DemosES2NEWT.java @@ -32,6 +32,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.WindowEvent; @@ -114,7 +115,7 @@ public class TestFBOMix2DemosES2NEWT extends UITestCase { if( 3 == c ) { demo.setMSAA(4); } else if( 6 == c ) { - new Thread() { + new InterruptSource.Thread() { @Override public void run() { glWindow.setSize(dw+64, dh+64); @@ -124,14 +125,14 @@ public class TestFBOMix2DemosES2NEWT extends UITestCase { } else if( 12 == c ) { demo.setMSAA(0); } else if( 15 == c ) { - new Thread() { + new InterruptSource.Thread() { @Override public void run() { glWindow.setSize(dw+128, dh+128); } }.start(); } else if( 18 == c ) { c=0; - new Thread() { + new InterruptSource.Thread() { @Override public void run() { glWindow.setSize(dw+256, dh+256); @@ -167,7 +168,7 @@ public class TestFBOMix2DemosES2NEWT extends UITestCase { } System.err.println("*** "+e); if(e.getKeyChar()=='f') { - new Thread() { + new InterruptSource.Thread() { public void run() { System.err.println("[set fullscreen pre]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); glWindow.setFullscreen(!glWindow.isFullscreen()); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java index 26d510a45..6c1e4b812 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOffThreadSharedContextMix2DemosES2NEWT.java @@ -48,7 +48,7 @@ import com.jogamp.opengl.test.junit.jogl.demos.GLFinishOnDisplay; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.jogl.demos.es2.Mix2TexturesES2; import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; - +import com.jogamp.common.util.InterruptSource; import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.SurfaceUpdatedListener; import com.jogamp.opengl.GL; @@ -192,7 +192,7 @@ public class TestFBOOffThreadSharedContextMix2DemosES2NEWT extends UITestCase { } if(9 == c) { c=0; - new Thread() { + new InterruptSource.Thread() { @Override public void run() { glWindow.setSize(dw+256, dh+256); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOnThreadSharedContext1DemoES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOnThreadSharedContext1DemoES2NEWT.java index 0586eef8e..1886d3d2a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOnThreadSharedContext1DemoES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestFBOOnThreadSharedContext1DemoES2NEWT.java @@ -46,7 +46,7 @@ import com.jogamp.opengl.util.texture.TextureIO; import com.jogamp.opengl.test.junit.jogl.demos.GLFinishOnDisplay; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.jogl.demos.es2.Mix2TexturesES2; - +import com.jogamp.common.util.InterruptSource; import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.SurfaceUpdatedListener; import com.jogamp.opengl.GL; @@ -178,7 +178,7 @@ public class TestFBOOnThreadSharedContext1DemoES2NEWT extends UITestCase { } if(9 == c) { c=0; - new Thread() { + new InterruptSource.Thread() { @Override public void run() { glWindow.setSize(dw+256, dh+256); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java new file mode 100644 index 000000000..1e264d21a --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java @@ -0,0 +1,247 @@ +/** + * 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.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLDrawableFactory; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLOffscreenAutoDrawable; +import com.jogamp.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import com.jogamp.opengl.JoglVersion; +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.GLEventListenerCounter; +import com.jogamp.opengl.test.junit.util.UITestCase; + +/** + * Testing producing {@link GLContext} instances of different {@link GLProfile}s + * using different {@link AbstractGraphicsDevice}s. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { + static final int widthStep = 800/4; + static final int heightStep = 600/4; + volatile int szStep = 2; + + static GLProfile getProfile(final AbstractGraphicsDevice device, final String profile) { + if( !GLProfile.isAvailable(device, profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } else { + return GLProfile.get(device, profile); + } + } + + void doTest(final boolean isEGL, final GLDrawableFactory factory, final AbstractGraphicsDevice device, + final GLCapabilitiesImmutable reqGLCaps, final GLEventListener demo) throws InterruptedException { + System.err.println("Factory: "+factory.getClass().getName()); + System.err.println("Requested GL Caps: "+reqGLCaps); + + // + // Create native OpenGL resources .. XGL/WGL/CGL .. + // equivalent to GLAutoDrawable methods: setVisible(true) + // + final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(device, reqGLCaps, null, widthStep*szStep, heightStep*szStep); + + Assert.assertNotNull(glad); + Assert.assertTrue(glad.isRealized()); + + // Check caps of NativeWindow config w/o GL + final CapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities(); + Assert.assertNotNull(chosenCaps); + + glad.display(); // force native context creation + + // Check caps of GLDrawable after realization + final GLCapabilitiesImmutable chosenGLCaps = glad.getChosenGLCapabilities(); + Assert.assertNotNull(chosenGLCaps); + System.err.println("Choosen GL Caps: "+chosenGLCaps); + + glad.addGLEventListener(demo); + final GLEventListenerCounter glelc = new GLEventListenerCounter(); + glad.addGLEventListener(glelc); + + glad.display(); // initial resize/display + + // 1 - szStep = 2 + Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getSurfaceWidth()+"x"+glad.getSurfaceHeight(), + AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep)); + glad.display(); + + // 2, 3 (resize + display) + szStep = 1; + glad.setSurfaceSize(widthStep*szStep, heightStep*szStep); + Assert.assertTrue("Size not reached: Expected "+(widthStep*szStep)+"x"+(heightStep*szStep)+", Is "+glad.getSurfaceWidth()+"x"+glad.getSurfaceHeight(), + AWTRobotUtil.waitForSize(glad, widthStep*szStep, heightStep*szStep)); + glad.display(); + + Thread.sleep(50); + + final AbstractGraphicsDevice adevice = glad.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); + glad.destroy(); + System.err.println("Fin isEGL "+isEGL+", "+adevice); + System.err.println("Fin "+glelc); + Assert.assertTrue("init count: "+glelc, glelc.initCount > 0); + Assert.assertTrue("reshape count: "+glelc, glelc.reshapeCount > 0); + Assert.assertTrue("display count: "+glelc, glelc.displayCount > 0); + Assert.assertTrue("dispose count: "+glelc, glelc.disposeCount > 0); + Assert.assertEquals("EGL/Desktop not matching: isEGL "+isEGL+", "+adevice, isEGL, adevice instanceof EGLGraphicsDevice); + } + + @Test + public void test00AvailableInfo() { + GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); + if(null != f) { + System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); + } + f = GLDrawableFactory.getEGLFactory(); + if(null != f) { + System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); + } + } + + @Test + public void test01ES2OnEGL() throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getEGLFactory(); + if( null == factory ) { + System.err.println("EGL Factory n/a"); + return; + } + final AbstractGraphicsDevice prodDevice = factory.getDefaultDevice(); + final GLProfile glp = getProfile(prodDevice, GLProfile.GLES2); + if(null != glp) { + Assert.assertTrue("Not a GLES2 profile but "+glp, glp.isGLES2()); + Assert.assertTrue("Not a GL2ES2 profile but "+glp, glp.isGL2ES2()); + } + if(null == glp) { + return; + } + final GLCapabilities reqGLCaps = new GLCapabilities(glp); + reqGLCaps.setOnscreen(false); + final GearsES2 demo = new GearsES2(1); + demo.setVerbose(false); + doTest(true /* isEGL */, factory, prodDevice, reqGLCaps, demo); + } + + @Test + public void test02GLOnEGL() throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getEGLFactory(); + if( null == factory ) { + System.err.println("EGL Factory n/a"); + return; + } + final AbstractGraphicsDevice prodDevice = factory.getDefaultDevice(); + final GLProfile glp = getProfile(prodDevice, GLProfile.GL2GL3); + if(null != glp) { + Assert.assertTrue("Not a GL2GL3 profile but "+glp, glp.isGL2GL3()); + } + if(null == glp || !glp.isGL2ES2()) { + if( null != glp ) { + System.err.println("Not a GL2ES2 profile but "+glp); + } + return; + } + final GLCapabilities reqGLCaps = new GLCapabilities(glp); + reqGLCaps.setOnscreen(false); + final GearsES2 demo = new GearsES2(1); + demo.setVerbose(false); + doTest(true /* isEGL */, factory, prodDevice, reqGLCaps, demo); + } + + @Test + public void test11ES2OnDesktop() throws InterruptedException { + final GLDrawableFactory deskFactory = GLDrawableFactory.getDesktopFactory(); + if( null == deskFactory ) { + System.err.println("Desktop Factory n/a"); + return; + } + final AbstractGraphicsDevice prodDevice = deskFactory.getDefaultDevice(); + final GLProfile glp = getProfile(prodDevice, GLProfile.GLES2); + if(null != glp) { + Assert.assertTrue("Not a GLES2 profile but "+glp, glp.isGLES2()); + Assert.assertTrue("Not a GL2ES2 profile but "+glp, glp.isGL2ES2()); + } + if(null == glp) { + return; + } + final GLDrawableFactory prodFactory = GLDrawableFactory.getFactory(glp); + if( null == prodFactory ) { + System.err.println("Production Factory n/a"); + return; + } + final GLCapabilities reqGLCaps = new GLCapabilities(glp); + reqGLCaps.setOnscreen(false); + final GearsES2 demo = new GearsES2(1); + demo.setVerbose(false); + doTest(true /* isEGL */, prodFactory, prodDevice, reqGLCaps, demo); + } + + @Test + public void test12GLOnDesktop() throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); + if( null == factory ) { + System.err.println("Desktop Factory n/a"); + return; + } + final AbstractGraphicsDevice prodDevice = factory.getDefaultDevice(); + final GLProfile glp = getProfile(prodDevice, GLProfile.GL2GL3); + if(null != glp) { + Assert.assertTrue("Not a GL2GL3 profile but "+glp, glp.isGL2GL3()); + } + if(null == glp || !glp.isGL2ES2()) { + if( null != glp ) { + System.err.println("Not a GL2ES2 profile but "+glp); + } + return; + } + final GLCapabilities reqGLCaps = new GLCapabilities(glp); + reqGLCaps.setOnscreen(false); + final GearsES2 demo = new GearsES2(1); + demo.setVerbose(false); + doTest(false /* isEGL */, factory, prodDevice, reqGLCaps, demo); + } + + public static void main(final String args[]) throws IOException { + org.junit.runner.JUnitCore.main(TestGLAutoDrawableFactoryGLProfileDeviceNEWT.class.getName()); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java index 1e78691c4..8d26ebb82 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLContextSurfaceLockNEWT.java @@ -31,6 +31,7 @@ package com.jogamp.opengl.test.junit.jogl.acore; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; +import com.jogamp.common.util.InterruptSource; import com.jogamp.nativewindow.NativeSurface; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; @@ -194,8 +195,8 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { final Object sync = new Object(); final MyRunnable[] animTasks = new MyRunnable[animThreadCount]; final MyRunnable[] resizeTasks = new MyRunnable[animThreadCount]; - final Thread[] animThreads = new Thread[reszThreadCount]; - final Thread[] resizeThreads = new Thread[reszThreadCount]; + final InterruptSource.Thread[] animThreads = new InterruptSource.Thread[reszThreadCount]; + final InterruptSource.Thread[] resizeThreads = new InterruptSource.Thread[reszThreadCount]; System.err.println("animThreadCount "+animThreadCount+", frameCount "+frameCount); System.err.println("reszThreadCount "+reszThreadCount+", resizeCount "+resizeCount); @@ -204,12 +205,12 @@ public class TestGLContextSurfaceLockNEWT extends UITestCase { for(int i=0; i<animThreadCount; i++) { System.err.println("create anim task/thread "+i); animTasks[i] = new RudeAnimator(glWindow, frameCount, sync, i); - animThreads[i] = new Thread(animTasks[i], currentThreadName+"-anim"+i); + animThreads[i] = new InterruptSource.Thread(null, animTasks[i], currentThreadName+"-anim"+i); } for(int i=0; i<reszThreadCount; i++) { System.err.println("create resz task/thread "+i); resizeTasks[i] = new RudeResizer(glWindow, resizeCount, sync, i); - resizeThreads[i] = new Thread(resizeTasks[i], currentThreadName+"-resz"+i); + resizeThreads[i] = new InterruptSource.Thread(null, resizeTasks[i], currentThreadName+"-resz"+i); } myEventCounter.reset(); 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 dcee114e5..8319a1c22 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 @@ -32,7 +32,6 @@ import java.io.IOException; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GL2GL3; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLContext; import com.jogamp.opengl.GLDebugListener; @@ -58,6 +57,14 @@ public class TestGLDebug00NEWT extends UITestCase { static String dbgTstMsg0 = "Hello World"; static int dbgTstId0 = 42; + static GLProfile getGLProfile(final String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return GLProfile.get(profile); + } + public static class WindowContext { public final Window window; public final GLContext context; @@ -115,9 +122,7 @@ public class TestGLDebug00NEWT extends UITestCase { } - void test01GLDebug01EnableDisable(final boolean enable) throws InterruptedException { - final GLProfile glp = GLProfile.getDefault(); - + void testX1GLDebugEnableDisable(final GLProfile glp, final boolean enable) throws InterruptedException { final WindowContext winctx = createWindow(glp, enable); final String glDebugExt = winctx.context.getGLDebugMessageExtension(); System.err.println("glDebug extension: "+glDebugExt); @@ -131,19 +136,42 @@ public class TestGLDebug00NEWT extends UITestCase { } @Test - public void test01GLDebugDisabled() throws InterruptedException { - test01GLDebug01EnableDisable(false); + public void test01GL2GL3DebugDisabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, false); } @Test - public void test01GLDebugEnabled() throws InterruptedException { - test01GLDebug01EnableDisable(true); + public void test02GL2GL3DebugEnabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, true); } @Test - public void test02GLDebugError() throws InterruptedException { - final GLProfile glp = GLProfile.getDefault(); + public void test11GLES2DebugDisabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, false); + } + + @Test + public void test12GLES2DebugEnabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, true); + } + void testX2GLDebugError(final GLProfile glp) throws InterruptedException { final WindowContext winctx = createWindow(glp, true); final MyGLDebugListener myGLDebugListener = new MyGLDebugListener( @@ -164,8 +192,24 @@ public class TestGLDebug00NEWT extends UITestCase { } @Test - public void test03GLDebugInsert() throws InterruptedException { - final GLProfile glp = GLProfile.getDefault(); + public void test03GL2GL3DebugError() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX2GLDebugError(glp); + } + + @Test + public void test13GLES2DebugError() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX2GLDebugError(glp); + } + + void testX3GLDebugInsert(final GLProfile glp) throws InterruptedException { final WindowContext winctx = createWindow(glp, true); final MyGLDebugListener myGLDebugListener = new MyGLDebugListener(dbgTstMsg0, dbgTstId0); winctx.context.addGLDebugListener(myGLDebugListener); @@ -184,6 +228,23 @@ public class TestGLDebug00NEWT extends UITestCase { destroyWindow(winctx); } + @Test + public void test04GL2GL3DebugInsert() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX3GLDebugInsert(glp); + } + + @Test + public void test14GLES2DebugInsert() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX3GLDebugInsert(glp); + } public static void main(final String args[]) throws IOException { final String tstname = TestGLDebug00NEWT.class.getName(); 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 66733209c..43d207a0d 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 @@ -31,7 +31,6 @@ package com.jogamp.opengl.test.junit.jogl.acore; import java.io.IOException; import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GL2GL3; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLContext; @@ -54,6 +53,14 @@ public class TestGLDebug01NEWT extends UITestCase { static String dbgTstMsg0 = "Hello World"; static int dbgTstId0 = 42; + static GLProfile getGLProfile(final String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return GLProfile.get(profile); + } + GLWindow createWindow(final GLProfile glp, final boolean debugGL) { final GLCapabilities caps = new GLCapabilities(glp); // @@ -76,9 +83,7 @@ public class TestGLDebug01NEWT extends UITestCase { } - void test01GLDebug01EnableDisable(final boolean enable, final String dbgTstMsg, final int dbgTstId) throws InterruptedException { - final GLProfile glp = GLProfile.getDefault(); - + void testX1GLDebugEnableDisable(final GLProfile glp, final boolean enable, final String dbgTstMsg, final int dbgTstId) throws InterruptedException { final GLWindow window = createWindow(glp, enable); final GLContext ctx = window.getContext(); final MyGLDebugListener myGLDebugListener = new MyGLDebugListener(dbgTstMsg, dbgTstId); @@ -109,19 +114,42 @@ public class TestGLDebug01NEWT extends UITestCase { } @Test - public void test01GLDebug01Disabled() throws InterruptedException { - test01GLDebug01EnableDisable(false, null, -1); + public void test01GL2GL3DebugDisabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, false, null, -1); } @Test - public void test01GLDebug01Enabled() throws InterruptedException { - test01GLDebug01EnableDisable(true, dbgTstMsg0, dbgTstId0); + public void test02GL2GL3DebugEnabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, true, dbgTstMsg0, dbgTstId0); } @Test - public void test02GLDebug01Error() throws InterruptedException { - final GLProfile glp = GLProfile.getDefault(); + public void test11GLES2DebugDisabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, false, null, -1); + } + @Test + public void test12GLES2DebugEnabled() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX1GLDebugEnableDisable(glp, true, dbgTstMsg0, dbgTstId0); + } + + void testX3GLDebugError(final GLProfile glp) throws InterruptedException { final GLWindow window = createWindow(glp, true); final MyGLDebugListener myGLDebugListener = new MyGLDebugListener( @@ -144,6 +172,23 @@ public class TestGLDebug01NEWT extends UITestCase { destroyWindow(window); } + @Test + public void test03GL2GL3DebugError() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GL2GL3); + if( null == glp ) { + return; + } + testX3GLDebugError(glp); + } + + @Test + public void test13GLES2DebugError() throws InterruptedException { + final GLProfile glp = getGLProfile(GLProfile.GLES2); + if( null == glp ) { + return; + } + testX3GLDebugError(glp); + } public static void main(final String args[]) throws IOException { final String tstname = TestGLDebug01NEWT.class.getName(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java index 65925c6b5..d49c1e545 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java @@ -49,16 +49,27 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.Window; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.newt.parenting.NewtAWTReparentingKeyAdapter; +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; 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; +/** + * <p> + * The demo code uses {@link NewtReparentingKeyAdapter} including {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000}, and many more, see {@link #main(String[])} + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { static boolean singleBuffer = false; @@ -162,7 +173,7 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { } setDemoFields(demo1, glWindow1, false); glWindow1.addGLEventListener(demo1); - glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1, null)); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); frame1.setSize(frameSize0); setupFrameAndShow(frame1, newtCanvasAWT1); @@ -189,7 +200,7 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { end(animator1, frame1, glWindow1); if( waitForKey ) { - UITestCase.waitForKey("Continue"); + JunitTracer.waitForKey("Continue"); } } @@ -234,7 +245,7 @@ public class TestOffscreenLayer02NewtCanvasAWT extends UITestCase { } } if(waitForKey) { - UITestCase.waitForKey("Start"); + JunitTracer.waitForKey("Start"); } final String tstname = TestOffscreenLayer02NewtCanvasAWT.class.getName(); /* 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 index aef64e4e9..ae9dac003 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestPBufferDeadlockAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestPBufferDeadlockAWT.java @@ -43,6 +43,7 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.RunnableTask; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -82,7 +83,7 @@ public class TestPBufferDeadlockAWT extends UITestCase { 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(); + new InterruptSource.Thread(null, rTask, Thread.currentThread().getName()+"-Pbuffer_Creation").start(); try { System.err.println("BB.2"); rTask.getSyncObject().wait(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java index 81489df17..0987b2978 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java @@ -14,6 +14,7 @@ import javax.swing.Timer; import org.junit.Test; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.opengl.*; @@ -69,7 +70,7 @@ public class TestSharedExternalContextAWT { // which is suppose to lie outside of the JVM. // The thread is kept alive, since this detail // may be required for the OpenGL driver implementation. - final Thread thread = new Thread(runnable); + final Thread thread = new InterruptSource.Thread(null, runnable); thread.setDaemon(true); thread.start(); masterLatch.await(3, TimeUnit.SECONDS); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestVersionSemanticsNOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestVersionSemanticsNOUI.java index bbbd92e5e..07d9e2954 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestVersionSemanticsNOUI.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestVersionSemanticsNOUI.java @@ -141,6 +141,44 @@ public class TestVersionSemanticsNOUI extends SingletonJunitCase { curVersion.getClass(), currentCL, curVersionNumber, excludesStereoPackageAndAppletUtils); } + @Test + public void testVersionV231V23x_01patch() throws IllegalArgumentException, IOException, URISyntaxException { + // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE; + // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER; + final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_BINARY; + + final VersionNumberString preVersionNumber = new VersionNumberString("2.3.1"); + final File previousJar = new File("lib/v"+preVersionNumber.getVersionString()+"/"+jarFile); + + final ClassLoader currentCL = TestVersionSemanticsNOUI.class.getClassLoader(); + + VersionSemanticsUtil.testVersion(diffCriteria, expectedCompatibilityType, + previousJar, preVersionNumber, + curVersion.getClass(), currentCL, curVersionNumber, + excludesStereoPackageAndAppletUtils); + } + + @Test + public void testVersionV230V232() throws IllegalArgumentException, IOException, URISyntaxException { + testVersions(diffCriteria, Delta.CompatibilityType.BACKWARD_COMPATIBLE_BINARY, "2.3.0", "2.3.2", excludesStereoPackageAndAppletUtils); + } + + // @Test + public void testVersionV232V24x0() throws IllegalArgumentException, IOException, URISyntaxException { + final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE; + // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER; + // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_BINARY; + + final VersionNumberString preVersionNumber = new VersionNumberString("2.3.2"); + final File previousJar = new File("lib/v"+preVersionNumber.getVersionString()+"/"+jarFile); + + final ClassLoader currentCL = TestVersionSemanticsNOUI.class.getClassLoader(); + + VersionSemanticsUtil.testVersion(diffCriteria, expectedCompatibilityType, + previousJar, preVersionNumber, + curVersion.getClass(), currentCL, curVersionNumber, + excludesDefault); + } public static void main(final String args[]) throws IOException { final String tstname = TestVersionSemanticsNOUI.class.getName(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/anim/Bug898AnimatorFromEDTAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/anim/Bug898AnimatorFromEDTAWT.java index b30bb1192..4cdcbd10a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/anim/Bug898AnimatorFromEDTAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/anim/Bug898AnimatorFromEDTAWT.java @@ -30,6 +30,7 @@ package com.jogamp.opengl.test.junit.jogl.acore.anim; import java.awt.BorderLayout; import java.awt.Dimension; +import com.jogamp.common.util.InterruptSource; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; @@ -85,10 +86,10 @@ public class Bug898AnimatorFromEDTAWT extends javax.swing.JFrame { lastTime = time; animator.pause(); System.out.println(Thread.currentThread().getName()+": #"+step+" "+td+" ms: animator.pause(): paused "+animator); - new Thread() { + new InterruptSource.Thread() { public void run() { try { - Thread.sleep(1000); + java.lang.Thread.sleep(1000); } catch (final InterruptedException e) { e.printStackTrace(); } @@ -98,9 +99,9 @@ public class Bug898AnimatorFromEDTAWT extends javax.swing.JFrame { final long td = System.currentTimeMillis() - lastTime; if (animator.isPaused()) { animator.resume(); //Doesn't work on v2.0.2 or higher - System.out.println(Thread.currentThread().getName()+": #"+step+" "+td+" ms: animator.resume(): animating "+animator); + System.out.println(java.lang.Thread.currentThread().getName()+": #"+step+" "+td+" ms: animator.resume(): animating "+animator); } else { - System.out.println(Thread.currentThread().getName()+": #"+step+" "+td+" ms: animator.resume(): Ooops - not paused! - animating "+animator); + System.out.println(java.lang.Thread.currentThread().getName()+": #"+step+" "+td+" ms: animator.resume(): Ooops - not paused! - animating "+animator); } } } ); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug1225EventQueueInterruptedAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug1225EventQueueInterruptedAWT.java new file mode 100644 index 000000000..92dd7e344 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug1225EventQueueInterruptedAWT.java @@ -0,0 +1,378 @@ +/** + * Copyright 2015 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.awt; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Label; +import java.lang.Thread.UncaughtExceptionHandler; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +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 org.junit.Assert; + +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptedRuntimeException; +import com.jogamp.common.util.SourcedInterruptedException; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.awt.GLCanvas; + +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +/** + * Test to check if interrupt on AWT-EventQueue causes a malfunction in JOGL. + * <p> + * After tests are displaying an ever color rotating rectangle in an AWT component alone + * and with an additional GearsES2 within a GLCanvas. + * </p> + * <p> + * The AWT component is issuing an interrupt during paint on the AWT-EDT. + * </p> + * <p> + * The reporter claims that an interrupt on the AWT-EDT shall not disturb neither AWT nor JOGL's GLCanvas + * and rendering shall continue. + * <ul> + * <li>This seems to be true for JRE 1.8.0_60</li> + * <li>This seems to be false for JRE 1.7.0_45. This JRE's AWT-EDT even dies occasionally when interrupted.</li> + * </ul> + * </p> + * <p> + * The test passes on GNU/Linux and Windows using JRE 1.8.0_60. + * </p> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestBug1225EventQueueInterruptedAWT extends UITestCase { + static long durationPerTest = 1000; // ms + + private void setVisible(final JFrame frame, final boolean v) throws InterruptedException, InvocationTargetException { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.pack(); + // frame.setSize(new Dimension(800, 600)); + frame.setVisible(v); + }}); + } + private void dispose(final JFrame jFrame) throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jFrame.dispose(); + } } ) ; + } + + + @Test(timeout=180000) // TO 3 min + public void test01_NoGL() throws InterruptedException, InvocationTargetException { + testImpl(false); + } + + @Test(timeout=180000) // TO 3 min + public void test02_WithGL() throws InterruptedException, InvocationTargetException { + testImpl(true); + } + + class OurUncaughtExceptionHandler implements UncaughtExceptionHandler { + public volatile Thread thread = null; + public volatile Throwable exception = null; + + @Override + public void uncaughtException(final Thread t, final Throwable e) { + thread = t; + exception = e; + System.err.println("*** UncaughtException (this Thread "+Thread.currentThread().getName()+") : Thread <"+t.getName()+">, "+e.getClass().getName()+": "+e.getMessage()); + ExceptionUtils.dumpThrowable("", e); + } + } + void testImpl(final boolean useGL) throws InterruptedException, InvocationTargetException { + if( !AWTRobotUtil.isAWTEDTAlive() ) { + System.err.println("Test aborted: AWT not alive"); + return; + } + // Assume.assumeTrue("AWT not alive", AWTRobotUtil.isAWTEDTAlive()); + // Assert.assertTrue("AWT not alive", AWTRobotUtil.isAWTEDTAlive()); + final OurUncaughtExceptionHandler uncaughtHandler = new OurUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler( uncaughtHandler ); + + final Dimension csize = new Dimension(800, 400); + final JPanel panel = new JPanel(new GridLayout(2, 1)); + final GLCanvas glc; + final InterruptableGLEL iglel; + if( useGL ) { + glc = new GLCanvas(); + { + final GearsES2 gears = new GearsES2(); + gears.setVerbose(false); + glc.addGLEventListener(gears); + } + iglel = new InterruptableGLEL(); + glc.addGLEventListener(iglel); + glc.setSize(csize); + glc.setPreferredSize(csize); + panel.add(glc); + } else { + NativeWindowFactory.initSingleton(); + glc = null; + iglel = null; + final Label l = new Label("No GL Object"); + l.setSize(csize); + l.setPreferredSize(csize); + panel.add(l); + } + final InterruptingComponent icomp = new InterruptingComponent(); + panel.add(icomp); + icomp.setSize(csize); + icomp.setPreferredSize(csize); + + final JFrame frame = new JFrame(); + frame.setResizable(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + frame.getContentPane().add(panel, BorderLayout.CENTER); + setVisible(frame, true); + if( useGL ) { + Assert.assertTrue(AWTRobotUtil.waitForRealized(glc, true)); + } + Assert.assertTrue(AWTRobotUtil.waitForRealized(icomp, true)); + + final InterruptableLoop loop = new InterruptableLoop(icomp, glc); + final Thread thread = new Thread(loop); + + synchronized(loop) { + thread.start(); + try { + loop.notifyAll(); // wake-up startup-block + while( !loop.isRunning && !loop.shallStop ) { + loop.wait(); // wait until started + } + loop.ack = true; + loop.notifyAll(); // wake-up startup-block + } catch (final InterruptedException e) { + Assert.assertNull("while starting loop", new InterruptedRuntimeException(e)); + } + } + + for(int i=0; thread.isAlive() && null == loop.exception && null == uncaughtHandler.exception && i<100; i++) { + icomp.interruptAWTEventQueue(); + Thread.sleep(durationPerTest/100); + } + + loop.shallStop = true; + synchronized(loop) { + try { + loop.notifyAll(); // wake-up pause-block (opt) + while( loop.isRunning ) { + loop.wait(); // wait until stopped + } + } catch (final InterruptedException e) { + Assert.assertNull("while stopping loop", new InterruptedRuntimeException(e)); + } + } + + // + // Notifications only! + // + // Note: + // On JRE 1.8.0_60: Interrupt is cleared on AWT-EDT + // On JRE 1.7.0_45: Interrupt is *NOT* cleared on AWT-EDT + // + if( null != iglel && null != iglel.exception ) { + ExceptionUtils.dumpThrowable("GLEventListener", iglel.exception); + } + if( null != icomp.exception ) { + ExceptionUtils.dumpThrowable("InterruptingComponent", icomp.exception); + } + if( null != loop.exception ) { + ExceptionUtils.dumpThrowable("loop", loop.exception); + } + if( null != uncaughtHandler.exception ) { + ExceptionUtils.dumpThrowable("uncaughtHandler", uncaughtHandler.exception); + } + if( !AWTRobotUtil.isAWTEDTAlive() ) { + System.err.println("AWT is not alive anymore!!! Ooops"); + // cannot do anything anymore on AWT-EDT .. frame.dispose(); + } else { + dispose(frame); + } + + // + // Fail if interrupt was propagated to loop or uncaught handler + // + Assert.assertNull("Caught Exception in loop", loop.exception); + Assert.assertNull("Caught Exception via uncaughtHandler", uncaughtHandler.exception); + } + + static class InterruptableLoop implements Runnable { + public volatile Exception exception = null; + public volatile boolean shallStop = false; + public volatile boolean isRunning = false; + public volatile boolean ack = false; + final InterruptingComponent icomp; + final GLCanvas glc; + boolean alt = false;; + + InterruptableLoop(final InterruptingComponent icomp, final GLCanvas glc) { + this.icomp = icomp; + this.glc = glc; + } + + public void stop() { + shallStop = true; + } + + @Override + public void run() + { + synchronized ( this ) { + isRunning = true; + this.notifyAll(); + try { + while( !ack ) { + this.wait(); // wait until ack + } + this.notifyAll(); + } catch (final InterruptedException e) { + throw new InterruptedRuntimeException(e); + } + ack = false; + } + synchronized ( this ) { + try { + while( !shallStop ) { + if( alt ) { + icomp.repaint(); // issues paint of GLCanvas on AWT-EDT + } else if( null != glc ) { + // Avoid invokeAndWait(..) in GLCanvas.display() if AWT-EDT dies! + glc.repaint(); // issues paint of GLCanvas on AWT-EDT, which then issues display()! + } + alt = !alt; + Thread.sleep(16); + if( Thread.interrupted() ) { + final InterruptedRuntimeException e = new InterruptedRuntimeException(new InterruptedException("Interrupt detected in loop, thread: "+Thread.currentThread().getName())); + throw e; + } + } + } catch (final InterruptedException e) { + exception = SourcedInterruptedException.wrap(e); + ExceptionUtils.dumpThrowable("", exception); + } catch (final Exception e) { + exception = e; + ExceptionUtils.dumpThrowable("", exception); + } finally { + isRunning = false; + this.notifyAll(); + } + } + } + } + + static class InterruptableGLEL implements GLEventListener { + public volatile InterruptedException exception = null; + @Override + public void init(final GLAutoDrawable drawable) { + } + @Override + public void dispose(final GLAutoDrawable drawable) { + } + @Override + public void display(final GLAutoDrawable drawable) { + final Thread c = Thread.currentThread(); + if( c.isInterrupted() && null == exception ) { + exception = new InterruptedException("Interrupt detected in GLEventListener, thread: "+c.getName()); + drawable.removeGLEventListener(this); + } + } + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + } + } + + static class InterruptingComponent extends Component { + private static final long serialVersionUID = 1L; + public volatile InterruptedException exception = null; + + private volatile boolean doInterrupt = false; + + private final Color[] colors = + new Color[] { Color.BLACK, Color.BLUE, Color.DARK_GRAY, Color.GRAY, Color.LIGHT_GRAY }; + private int colorIdx = 0; + + public InterruptingComponent() { + } + + public void interruptAWTEventQueue() { + doInterrupt = true; + } + + @Override + public void paint(final Graphics g) + { + final Thread c = Thread.currentThread(); + if( c.isInterrupted() && null == exception ) { + exception = new InterruptedException("Interrupt detected in AWT Component, thread: "+c.getName()); + } + + g.setColor(colors[colorIdx++]); + if( colorIdx >= colors.length ) { + colorIdx = 0; + } + g.fillRect(0, 0, getWidth(), getHeight()); + + if(doInterrupt) { + System.err.println("Thread "+c.getName()+": *Interrupting*"); + doInterrupt = false; + c.interrupt(); + } + } + } + + public static void main(final String[] args) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = MiscUtils.atol(args[++i], durationPerTest); + } + } + org.junit.runner.JUnitCore.main(TestBug1225EventQueueInterruptedAWT.class.getName()); + } +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug1245JTabbedPanelCrashAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug1245JTabbedPanelCrashAWT.java new file mode 100644 index 000000000..bc52238bb --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug1245JTabbedPanelCrashAWT.java @@ -0,0 +1,228 @@ +/** + * Copyright 2013 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.awt; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.awt.GLCanvas; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.GLEventListenerCounter; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +/** + * Bug 1245 + * <p> + * https://jogamp.org/bugzilla/show_bug.cgi?id=1245 + * </p> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestBug1245JTabbedPanelCrashAWT extends UITestCase { + + static long durationPerTest = 500*4; // ms + static boolean manual = false; + + @SuppressWarnings("serial") + static class View3D extends JPanel { + final GLCanvas canvas; + final Animator animator; + final int num; + + public View3D(final int num) { + this.num = num; + this.setLayout(new BorderLayout()); + canvas = new GLCanvas(); + canvas.setSize(new Dimension(100, 100)); + canvas.setMinimumSize(new Dimension(100, 100)); + add(canvas, BorderLayout.CENTER); + animator = new Animator(); + animator.add(canvas); + // could do animator.start() here as well, + // just to be nice - we start/stop at add/remove Notify + } + @Override + public void addNotify() { + System.err.println("View3D["+num+"].addNotify()"); + super.addNotify(); + if( null != animator ) { + animator.start(); + } + } + @Override + public void removeNotify() { + System.err.println("View3D["+num+"].removeNotify()"); + if( null != animator ) { + animator.stop(); + } + super.removeNotify(); + } + + public String getGLCanvasStats() { + return "GLCanvas: comp "+canvas.getBounds()+", visible "+canvas.isVisible()+", showing "+canvas.isShowing()+ + ", displayable "+canvas.isDisplayable()+", "+canvas.getSurfaceWidth()+"x"+canvas.getSurfaceHeight()+ + ", "+canvas.getChosenGLCapabilities()+", drawable 0x"+Long.toHexString(canvas.getHandle()); + } + } + + final GLEventListenerCounter glelCounter = new GLEventListenerCounter(); + + private JTabbedPane createAndShowGUI(final JFrame frame, final View3D[] views) { + final JPanel panel = new JPanel(new GridLayout(1, 1)); + final JTabbedPane tabbedPanel = new JTabbedPane(); + for(int i=0; i<views.length; i++) { + final GLEventListener demo; + if( i%2 == 0 ) { + final GearsES2 gears = new GearsES2(1); + gears.setVerbose(false); + demo = gears; + } else { + final RedSquareES2 red = new RedSquareES2(1); + red.setVerbose(false); + demo = red; + } + views[i] = new View3D(i); + views[i].canvas.addGLEventListener(glelCounter); + views[i].canvas.addGLEventListener(demo); + tabbedPanel.addTab("Tab "+i, null, views[i], "Does nothing"); + } + tabbedPanel.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + tabbedPanel.addChangeListener(new javax.swing.event.ChangeListener() { + @Override + public void stateChanged(final javax.swing.event.ChangeEvent evt) { + final int idx = tabbedPanel.getSelectedIndex(); + if( 0 <= idx && idx < views.length ) { + System.err.println("Pane["+idx+"]: State Changed: "+evt); + System.err.println("Pane["+idx+"]: "+views[idx].getGLCanvasStats()); + } + } + }); + + panel.add(tabbedPanel); + frame.add(panel, BorderLayout.CENTER); + frame.setSize(640,480); + + return tabbedPanel; + } + + private static String id(final Object obj) { return "0x"+Integer.toHexString(obj.hashCode()); } + + @BeforeClass + public static void startup() { + GLProfile.initSingleton(); + } + + @Test + public void test01() throws InterruptedException, InvocationTargetException { + final JFrame frame = new JFrame("Java3DApplication"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + final View3D[] views = new View3D[4]; + final JTabbedPane[] tabbedPane = { null }; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //Turn off metal's use of bold fonts + UIManager.put("swing.boldMetal", Boolean.FALSE); + tabbedPane[0] = createAndShowGUI(frame, views); + System.err.println("XXX SetVisible ON XXX"); + frame.setVisible(true); + } } ); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); + for(int i=0; i<views.length; i++) { + System.err.printf("View "+i+": "+views[i]+",%n "+views[i].getGLCanvasStats()+"%n%n"); + } + + System.err.println("XXX POST.VISIBLE: "+glelCounter); + if(manual) { + Thread.sleep(durationPerTest); + System.err.println("XXX POST.ACTION: "+glelCounter); + } else { + final JTabbedPane tabbedPanel = tabbedPane[0]; + + for(int i=0; i<views.length; i++) { + Thread.sleep(durationPerTest/views.length); + switchTab(tabbedPanel, views, i, (i+1)%views.length); + } + Thread.sleep(durationPerTest/views.length); + switchTab(tabbedPanel, views, 0, 1); + + Thread.sleep(durationPerTest/views.length); + switchTab(tabbedPanel, views, 1, 0); + + System.err.println("XXX POST.ACTION: "+glelCounter); + Assert.assertTrue(glelCounter.initCount >= views.length); + } + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + System.err.println("XXX SetVisible OFF XXX"); + frame.dispose(); + } }); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, false)); + System.err.println("XXX POST.DISPOSE: "+glelCounter); + } + + void switchTab(final JTabbedPane tabbedPanel, final View3D[] views, final int thisId, final int nextId) throws InvocationTargetException, InterruptedException { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + System.err.println("XXXX Panel("+id(views[thisId])+" -> Panel("+id(views[nextId])+") START"); + tabbedPanel.setSelectedIndex(nextId); + }}); + } + + public static void main(final 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(TestBug1245JTabbedPanelCrashAWT.class.getName()); + } +} 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 f3c2734b5..dfd2489e2 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 @@ -28,6 +28,8 @@ package com.jogamp.opengl.test.junit.jogl.caps; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; @@ -92,12 +94,12 @@ public class TestTranslucencyNEWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setFullscreen(!f_glWindow.isFullscreen()); } }.start(); } else if(e.getKeyChar()=='d') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setUndecorated(!f_glWindow.isUndecorated()); } }.start(); @@ -157,7 +159,7 @@ public class TestTranslucencyNEWT extends UITestCase { } } if( waitForKey ) { - UITestCase.waitForKey("main"); + JunitTracer.waitForKey("main"); } org.junit.runner.JUnitCore.main(TestTranslucencyNEWT.class.getName()); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/GLClearOnInitReshape.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/GLClearOnInitReshape.java new file mode 100644 index 000000000..46be7ef0a --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/GLClearOnInitReshape.java @@ -0,0 +1,64 @@ +/** + * Copyright 2015 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; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; + +public class GLClearOnInitReshape implements GLEventListener { + int lastWidth, lastHeight; + boolean doClear; + + @Override + public void init(final GLAutoDrawable drawable) { + lastWidth = drawable.getSurfaceWidth(); + lastHeight = drawable.getSurfaceHeight(); + doClear = true; + } + + @Override + public void dispose(final GLAutoDrawable drawable) { } + + @Override + public void display(final GLAutoDrawable drawable) { + if( doClear ) { + drawable.getGL().glClear(GL.GL_COLOR_BUFFER_BIT); + doClear = false; + } + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + if( lastHeight != height || lastWidth != width ) { + doClear = true; + lastWidth = width; + lastHeight = height; + } + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/PointsDemoES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/PointsDemoES1.java index 7189db1f3..e8acb0baf 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/PointsDemoES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/PointsDemoES1.java @@ -181,9 +181,7 @@ public class PointsDemoES1 extends PointsDemo { // Thread.dumpStack(); final GL2ES1 gl = glad.getGL().getGL2ES1(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) - } + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) // Set location in front of camera gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/RedSquareES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/RedSquareES1.java index 60ac6b233..7eebf4489 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/RedSquareES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/RedSquareES1.java @@ -141,9 +141,7 @@ public class RedSquareES1 implements GLEventListener, TileRendererBase.TileRende @Override public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { final GL2ES1 gl = glad.getGL().getGL2ES1(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); - } + gl.setSwapInterval(swapInterval); reshapeImpl(gl, x, y, width, height, width, height); } 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 771748a33..432652701 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 @@ -28,6 +28,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es1.newt; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; @@ -92,12 +93,12 @@ public class TestGearsES1NEWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setFullscreen(!f_glWindow.isFullscreen()); } }.start(); } else if(e.getKeyChar()=='d') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setUndecorated(!f_glWindow.isUndecorated()); } }.start(); 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 9bf04a75f..769183e82 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 @@ -28,6 +28,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es1.newt; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; @@ -90,12 +91,12 @@ public class TestRedSquareES1NEWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setFullscreen(!f_glWindow.isFullscreen()); } }.start(); } else if(e.getKeyChar()=='d') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setUndecorated(!f_glWindow.isUndecorated()); } }.start(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/FBOMix2DemosES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/FBOMix2DemosES2.java index ff88af50a..de2d3458a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/FBOMix2DemosES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/FBOMix2DemosES2.java @@ -267,9 +267,7 @@ public class FBOMix2DemosES2 implements GLEventListener { public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) - } + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) System.err.println("**** Reshape: "+width+"x"+height); resetFBOs(gl, drawable); 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 e1abcc752..c0a4756e7 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 @@ -319,9 +319,7 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { if( !isInit ) { return; } final GL2ES2 gl = glad.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); - } + gl.setSwapInterval(swapInterval); reshapeImpl(gl, x, y, width, height, width, height); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LandscapeES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LandscapeES2.java index a504ec1ed..18c0ffd68 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LandscapeES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LandscapeES2.java @@ -128,9 +128,7 @@ public class LandscapeES2 implements GLEventListener { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) - } + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) shaderState.useProgram(gl, true); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LineSquareXDemoES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LineSquareXDemoES2.java new file mode 100644 index 000000000..2169b93d0 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/LineSquareXDemoES2.java @@ -0,0 +1,189 @@ +/** + * Copyright (C) 2015 JogAmp Community. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.jogamp.opengl.test.junit.jogl.demos.es2; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.opengl.util.ImmModeSink; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; + +public class LineSquareXDemoES2 implements GLEventListener { + + private boolean multisample, clearBuffers; + private final ShaderState st; + private final PMVMatrix pmvMatrix; + private ShaderProgram sp0; + private GLUniformData pmvMatrixUniform; + private ImmModeSink immModeSink; + + public LineSquareXDemoES2(final boolean multisample) { + this.multisample = multisample; + this.clearBuffers = true; + st = new ShaderState(); + st.setVerbose(true); + pmvMatrix = new PMVMatrix(); + } + + public void setClearBuffers(final boolean v) { clearBuffers = v; } + + public void init(final GLAutoDrawable glad) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + + System.err.println(); + System.err.println("req. msaa: "+multisample); + System.err.println("Requested: " + glad.getNativeSurface().getGraphicsConfiguration().getRequestedCapabilities()); + multisample = multisample && glad.getChosenGLCapabilities().getNumSamples() > 0 ; + System.err.println("Chosen : " + glad.getChosenGLCapabilities()); + System.err.println("has msaa: "+multisample); + System.err.println(); + + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, LineSquareXDemoES2.class, "shader", + "shader/bin", "mgl_default_xxx", true); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, LineSquareXDemoES2.class, "shader", + "shader/bin", "mgl_default_xxx", true); + vp0.defaultShaderCustomization(gl, true, true); + fp0.defaultShaderCustomization(gl, true, true); + + sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + st.attachShaderProgram(gl, sp0, true); + + pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + st.ownUniform(pmvMatrixUniform); + st.uniform(gl, pmvMatrixUniform); + + final float c = 0f; + final float eX = 0.5f; + final float eH = 0.98f; + final float e2 = 1f; + + // Using predef array names, see + // GLPointerFuncUtil.getPredefinedArrayIndexName(glArrayIndex); + immModeSink = ImmModeSink.createGLSL(20*2, + 3, GL.GL_FLOAT, // vertex + 4, GL.GL_FLOAT, // color + 0, GL.GL_FLOAT, // normal + 0, GL.GL_FLOAT, // texCoords + GL.GL_STATIC_DRAW, st); + immModeSink.glBegin(GL.GL_LINES); + + // Rectangle + immModeSink.glVertex3f(-eX, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-eX, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-eX, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eX, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eX, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eX, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eX, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-eX, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + + // Square + immModeSink.glVertex3f(-eH, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-eH, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-eH, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eH, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eH, eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eH, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( eH, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-eH, -eH, 0f); immModeSink.glColor4f( c, c, c, c ); + + // X + immModeSink.glVertex3f(-e2, -e2, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( e2, e2, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f(-e2, e2, 0f); immModeSink.glColor4f( c, c, c, c ); + immModeSink.glVertex3f( e2, -e2, 0f); immModeSink.glColor4f( c, c, c, c ); + + immModeSink.glEnd(gl, false); + + st.useProgram(gl, false); + } + + public void dispose(final GLAutoDrawable glad) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + immModeSink.destroy(gl); + immModeSink = null; + st.destroy(gl); + } + + public void display(final GLAutoDrawable glad) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + if (multisample) { + gl.glEnable(GL.GL_MULTISAMPLE); + } + if( clearBuffers ) { + final float c = 0.9f; + gl.glClearColor(c, c, c, 0); + // gl.glEnable(GL.GL_DEPTH_TEST); + // gl.glDepthFunc(GL.GL_LESS); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + } + + st.useProgram(gl, true); + + immModeSink.draw(gl, true); + + st.useProgram(gl, false); + } + + // Unused routines + public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { + System.err.println("reshape .."); + final GL2ES2 gl = glad.getGL().getGL2ES2(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + final float left, right, bottom, top; + if( height > width ) { + final float a = (float)height / (float)width; + left = -1.0f; + right = 1.0f; + bottom = -a; + top = a; + } else { + final float a = (float)width / (float)height; + left = -a; + right = a; + bottom = -1.0f; + top = 1.0f; + } + // pmvMatrix.glOrthof(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); + // pmvMatrix.glOrthof(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 10.0f); + pmvMatrix.glOrthof(left, right, top, bottom, 0.0f, 10.0f); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + + public void displayChanged(final GLAutoDrawable drawable, final boolean modeChanged, final boolean deviceChanged) { + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/Mix2TexturesES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/Mix2TexturesES2.java index 6d202707e..3ec383ad8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/Mix2TexturesES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/Mix2TexturesES2.java @@ -181,9 +181,7 @@ public class Mix2TexturesES2 implements GLEventListener { public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) - } + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); pmvMatrix.glLoadIdentity(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/PointsDemoES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/PointsDemoES2.java index 673552c5f..d59c1bb84 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/PointsDemoES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/PointsDemoES2.java @@ -186,9 +186,7 @@ public class PointsDemoES2 extends PointsDemo { // Thread.dumpStack(); final GL2ES2 gl = glad.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) - } + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) st.useProgram(gl, true); // Set location in front of camera 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 a0afef87a..eb96d1593 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 @@ -52,6 +52,7 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende private int swapInterval = 0; private float aspect = 1.0f; private boolean doRotate = true; + private boolean verbose = true; private boolean clearBuffers = true; private TileRendererBase tileRendererInUse = null; private boolean doRotateBeforePrinting; @@ -87,16 +88,21 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende public void setAspect(final float aspect) { this.aspect = aspect; } public void setDoRotation(final boolean rotate) { this.doRotate = rotate; } public void setClearBuffers(final boolean v) { clearBuffers = v; } + public void setVerbose(final boolean v) { verbose = v; } @Override public void init(final GLAutoDrawable glad) { - System.err.println(Thread.currentThread()+" RedSquareES2.init: tileRendererInUse "+tileRendererInUse); + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.init: tileRendererInUse "+tileRendererInUse); + } final GL2ES2 gl = glad.getGL().getGL2ES2(); - System.err.println("RedSquareES2 init on "+Thread.currentThread()); - System.err.println("Chosen GLCapabilities: " + glad.getChosenGLCapabilities()); - System.err.println("INIT GL IS: " + gl.getClass().getName()); - System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); + if(verbose) { + System.err.println("RedSquareES2 init on "+Thread.currentThread()); + System.err.println("Chosen GLCapabilities: " + glad.getChosenGLCapabilities()); + System.err.println("INIT GL IS: " + gl.getClass().getName()); + System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); + } if( !gl.hasGLSL() ) { System.err.println("No GLSL available, no rendering."); return; @@ -149,7 +155,9 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende st.useProgram(gl, false); t0 = System.currentTimeMillis(); - System.err.println(Thread.currentThread()+" RedSquareES2.init FIN"); + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.init FIN"); + } } @Override @@ -192,9 +200,7 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende @Override public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { final GL2ES2 gl = glad.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); - } + gl.setSwapInterval(swapInterval); reshapeImpl(gl, x, y, width, height, width, height); } @@ -208,7 +214,9 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende } void reshapeImpl(final GL2ES2 gl, final int tileX, final int tileY, final int tileWidth, final int tileHeight, final int imageWidth, final int imageHeight) { - System.err.println(Thread.currentThread()+" RedSquareES2.reshape "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", tileRendererInUse "+tileRendererInUse); + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.reshape "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", tileRendererInUse "+tileRendererInUse); + } // Thread.dumpStack(); if( !gl.hasGLSL() ) { return; @@ -249,7 +257,9 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende @Override public void dispose(final GLAutoDrawable glad) { - System.err.println(Thread.currentThread()+" RedSquareES2.dispose: tileRendererInUse "+tileRendererInUse); + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.dispose: tileRendererInUse "+tileRendererInUse); + } final GL2ES2 gl = glad.getGL().getGL2ES2(); if( !gl.hasGLSL() ) { return; @@ -257,6 +267,8 @@ public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRende st.destroy(gl); st = null; pmvMatrix = null; - System.err.println(Thread.currentThread()+" RedSquareES2.dispose FIN"); + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.dispose FIN"); + } } } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareMappedES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareMappedES2.java index 9dab97d16..3b526401d 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareMappedES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareMappedES2.java @@ -211,9 +211,7 @@ public class RedSquareMappedES2 implements GLEventListener, TileRendererBase.Til @Override public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { final GL2ES2 gl = glad.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); - } + gl.setSwapInterval(swapInterval); reshapeImpl(gl, x, y, width, height, width, height); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureDraw02ES2ListenerFBO.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureDraw02ES2ListenerFBO.java index 2d6745594..e360b5987 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureDraw02ES2ListenerFBO.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TextureDraw02ES2ListenerFBO.java @@ -230,9 +230,7 @@ public class TextureDraw02ES2ListenerFBO implements GLEventListener { public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) - } + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) System.err.println("**** Reshape.Reset: "+width+"x"+height); if( keepTextureBound ) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/CrossFadePlayer.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/CrossFadePlayer.java index b2ebc7068..cc4096672 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/CrossFadePlayer.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/CrossFadePlayer.java @@ -29,6 +29,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.av;
import com.jogamp.common.net.Uri;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.opengl.util.av.AudioSink;
import com.jogamp.opengl.util.av.GLMediaPlayer;
import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener;
@@ -73,7 +74,7 @@ public class CrossFadePlayer System.out.println("Duration: " + mp.getDuration() + "ms");
System.out.println("Volume: " + mp.getAudioVolume());
System.out.println("player.initGL()...");
- new Thread() {
+ new InterruptSource.Thread() {
public void run() {
try {
mp.initGL(null);
@@ -98,7 +99,7 @@ public class CrossFadePlayer stop = true;
} else {
System.err.println("Player State: EOS");
- new Thread() {
+ new InterruptSource.Thread() {
public void run() {
System.out.println("mp.setPlaySpeed(1f) returned: " + mp.setPlaySpeed(1f));
mp.seek(0);
@@ -112,7 +113,7 @@ public class CrossFadePlayer if( null != se ) {
se.printStackTrace();
}
- new Thread() {
+ new InterruptSource.Thread() {
public void run() {
System.out.println("terminating...");
stop = true;
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java index b938adb53..a8dede526 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java @@ -42,10 +42,12 @@ import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLProfile; import com.jogamp.common.net.Uri; +import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.font.Font; +import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.Window; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; @@ -57,7 +59,6 @@ import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.test.junit.graph.TextRendererGLELBase; import com.jogamp.opengl.test.junit.jogl.demos.es2.TextureSequenceCubeES2; 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.av.GLMediaPlayer; import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener; @@ -75,7 +76,7 @@ public class MovieCube implements GLEventListener { private TextureSequenceCubeES2 cube=null; private GLMediaPlayer mPlayer=null; private int swapInterval = 1; - private int swapIntervalSet = -1; + private boolean swapIntervalSet = true; private long lastPerfPos = 0; private volatile boolean resetGLState = false; @@ -116,7 +117,7 @@ public class MovieCube implements GLEventListener { resetGLState(); } if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { - new Thread() { + new InterruptSource.Thread() { public void run() { // loop for-ever .. mPlayer.seek(0); @@ -246,7 +247,7 @@ public class MovieCube implements GLEventListener { final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, v-sync %d", pts, mPlayer.getDuration() / 1000f, mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(), - aspect, mPlayer.getFramerate(), lfps, tfps, swapIntervalSet); + aspect, mPlayer.getFramerate(), lfps, tfps, swapInterval); final String text2 = String.format("audio: id %d, kbps %d, codec %s", mPlayer.getAID(), mPlayer.getAudioBitrate()/1000, mPlayer.getAudioCodec()); final String text3 = String.format("video: id %d, kbps %d, codec %s", @@ -278,10 +279,13 @@ public class MovieCube implements GLEventListener { int pts1 = 0; switch(e.getKeySymbol()) { case KeyEvent.VK_V: { - switch(swapIntervalSet) { - case 0: swapInterval = 1; break; - default: swapInterval = 0; break; + switch(swapInterval) { + case 0: swapInterval = -1; break; + case -1: swapInterval = 1; break; + case 1: swapInterval = 0; break; + default: swapInterval = 1; break; } + swapIntervalSet = true; break; } case KeyEvent.VK_O: displayOSD = !displayOSD; break; @@ -362,7 +366,7 @@ public class MovieCube implements GLEventListener { cube = new TextureSequenceCubeES2(mPlayer, false, zoom0, rotx, roty); if(waitForKey) { - UITestCase.waitForKey("Init>"); + JunitTracer.waitForKey("Init>"); } if( GLMediaPlayer.State.Initialized == mPlayer.getState() ) { @@ -433,12 +437,14 @@ public class MovieCube implements GLEventListener { @Override public void display(final GLAutoDrawable drawable) { - if(-1 != swapInterval) { + if( swapIntervalSet ) { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) + final int _swapInterval = swapInterval; + gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there) drawable.getAnimator().resetFPSCounter(); - swapIntervalSet = swapInterval; - swapInterval = -1; + swapInterval = gl.getSwapInterval(); + System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval); + swapIntervalSet = false; } if(null == mPlayer) { return; } @@ -594,7 +600,7 @@ public class MovieCube implements GLEventListener { if( null != se ) { se.printStackTrace(); } - new Thread() { + new InterruptSource.Thread() { public void run() { window.destroy(); } }.start(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSBSStereo.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSBSStereo.java index e936bf991..9b9073721 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSBSStereo.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSBSStereo.java @@ -42,6 +42,7 @@ import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.common.net.Uri; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; @@ -800,7 +801,7 @@ public class MovieSBSStereo implements StereoGLEventListener { static class StereoGLMediaEventListener implements GLMediaEventListener { void destroyWindow(final Window window) { - new Thread() { + new InterruptSource.Thread() { public void run() { window.destroy(); } }.start(); @@ -846,7 +847,7 @@ public class MovieSBSStereo implements StereoGLEventListener { destroy = true; } else { System.err.println("MovieSimple State: EOS"); - new Thread() { + new InterruptSource.Thread() { public void run() { mp.setPlaySpeed(1f); mp.seek(0); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java index 22dfa923e..25ce93597 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java @@ -47,10 +47,12 @@ import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.common.net.Uri; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.font.Font; +import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.Window; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; @@ -65,7 +67,6 @@ import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.test.junit.graph.TextRendererGLELBase; 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.GLArrayDataServer; import com.jogamp.opengl.util.PMVMatrix; @@ -105,7 +106,7 @@ public class MovieSimple implements GLEventListener { private int effects = EFFECT_NORMAL; private float alpha = 1.0f; private int swapInterval = 1; - private int swapIntervalSet = -1; + private boolean swapIntervalSet = true; private GLMediaPlayer mPlayer; private final boolean mPlayerShared; @@ -185,7 +186,7 @@ public class MovieSimple implements GLEventListener { final float aspect = (float)mPlayer.getWidth() / (float)mPlayer.getHeight(); final String ptsPrec = null != regionFPS ? "3.1" : "3.0"; - final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, v-sync %d", + final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, v-sync %b", pts, mPlayer.getDuration() / 1000f, mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(), aspect, mPlayer.getFramerate(), lfps, tfps, swapIntervalSet); @@ -265,10 +266,13 @@ public class MovieSimple implements GLEventListener { int pts1 = 0; switch(e.getKeySymbol()) { case KeyEvent.VK_V: { - switch(swapIntervalSet) { - case 0: swapInterval = 1; break; - default: swapInterval = 0; break; + switch(swapInterval) { + case 0: swapInterval = -1; break; + case -1: swapInterval = 1; break; + case 1: swapInterval = 0; break; + default: swapInterval = 1; break; } + swapIntervalSet = true; break; } case KeyEvent.VK_O: displayOSD = !displayOSD; break; @@ -352,7 +356,7 @@ public class MovieSimple implements GLEventListener { resetGLState(); } if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { - new Thread() { + new InterruptSource.Thread() { public void run() { // loop for-ever .. mPlayer.seek(0); @@ -483,7 +487,7 @@ public class MovieSimple implements GLEventListener { ", "+drawable.getClass().getName()+", "+drawable); if(waitForKey) { - UITestCase.waitForKey("Init>"); + JunitTracer.waitForKey("Init>"); } final Texture tex; try { @@ -736,11 +740,13 @@ public class MovieSimple implements GLEventListener { @Override public void display(final GLAutoDrawable drawable) { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) + if( swapIntervalSet ) { + final int _swapInterval = swapInterval; + gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there) drawable.getAnimator().resetFPSCounter(); - swapIntervalSet = swapInterval; - swapInterval = -1; + swapInterval = gl.getSwapInterval(); + System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval); + swapIntervalSet = false; } if(null == mPlayer) { return; } @@ -802,7 +808,7 @@ public class MovieSimple implements GLEventListener { static class MyGLMediaEventListener implements GLMediaEventListener { void destroyWindow(final Window window) { - new Thread() { + new InterruptSource.Thread() { public void run() { window.destroy(); } }.start(); @@ -836,7 +842,7 @@ public class MovieSimple implements GLEventListener { /** * Kick off player w/o GLEventListener, i.e. for audio only. * - new Thread() { + new InterruptSource.Thread() { public void run() { try { mp.initGL(null); @@ -868,7 +874,7 @@ public class MovieSimple implements GLEventListener { } else { System.err.println("MovieSimple State: EOS"); if( loopEOS ) { - new Thread() { + new InterruptSource.Thread() { public void run() { mp.setPlaySpeed(1f); mp.seek(0); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java index 2e805d8fd..503878c65 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java @@ -158,7 +158,15 @@ public class TestGearsES2AWT extends UITestCase { private void setTitle(final Frame frame, final GLCanvas glc, final GLCapabilitiesImmutable caps) { final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl"; final java.awt.Rectangle b = glc.getBounds(); - frame.setTitle("GLCanvas["+capsA+"], swapI "+swapInterval+", win: ["+b.x+"/"+b.y+" "+b.width+"x"+b.height+"], pix: "+glc.getSurfaceWidth()+"x"+glc.getSurfaceHeight()); + final float[] minSurfacePixelScale = glc.getMinimumSurfaceScale(new float[2]); + final float[] maxSurfacePixelScale = glc.getMaximumSurfaceScale(new float[2]); + final float[] reqSurfacePixelScale = glc.getRequestedSurfaceScale(new float[2]); + final float[] hasSurfacePixelScale = glc.getCurrentSurfaceScale(new float[2]); + frame.setTitle("GLCanvas["+capsA+"], swapI "+swapInterval+", win: ["+b.x+"/"+b.y+" "+b.width+"x"+b.height+"], pix: "+glc.getSurfaceWidth()+"x"+glc.getSurfaceHeight()+ + ", scale[min "+minSurfacePixelScale[0]+"x"+minSurfacePixelScale[1]+", max "+ + maxSurfacePixelScale[0]+"x"+maxSurfacePixelScale[1]+", req "+ + reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" -> has "+ + hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+"]"); } protected void runTestGL(final GLCapabilities caps, final ResizeBy resizeBy, final FrameLayout frameLayout) throws InterruptedException, InvocationTargetException { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java index dfc2d1165..a41e4b9e7 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java @@ -31,6 +31,8 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.awt; import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; import java.lang.reflect.InvocationTargetException; import com.jogamp.nativewindow.ScalableSurface; @@ -63,6 +65,7 @@ import com.jogamp.newt.event.TraceKeyAdapter; import com.jogamp.newt.event.TraceWindowAdapter; import com.jogamp.newt.event.awt.AWTKeyAdapter; import com.jogamp.newt.event.awt.AWTWindowAdapter; +import com.jogamp.opengl.test.junit.jogl.demos.GLClearOnInitReshape; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; @@ -78,6 +81,7 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { static boolean forceES3 = false; static boolean forceGL3 = false; static boolean forceGLFFP = false; + static int demoType = 1; static boolean shallUsePBuffer = false; static boolean shallUseBitmap = false; static boolean useMSAA = false; @@ -118,17 +122,41 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { private void setTitle(final JFrame frame, final GLJPanel glc, final GLCapabilitiesImmutable caps) { final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl"; final java.awt.Rectangle b = glc.getBounds(); - frame.setTitle("GLJPanel["+capsA+"], swapI "+swapInterval+", win: ["+b.x+"/"+b.y+" "+b.width+"x"+b.height+"], pix: "+glc.getSurfaceWidth()+"x"+glc.getSurfaceHeight()); + + final float[] minSurfacePixelScale = glc.getMinimumSurfaceScale(new float[2]); + final float[] maxSurfacePixelScale = glc.getMaximumSurfaceScale(new float[2]); + final float[] reqSurfacePixelScale = glc.getRequestedSurfaceScale(new float[2]); + final float[] hasSurfacePixelScale = glc.getCurrentSurfaceScale(new float[2]); + frame.setTitle("GLJPanel["+capsA+"], swapI "+swapInterval+", win: ["+b.x+"/"+b.y+" "+b.width+"x"+b.height+"], pix: "+glc.getSurfaceWidth()+"x"+glc.getSurfaceHeight()+ + ", scale[min "+minSurfacePixelScale[0]+"x"+minSurfacePixelScale[1]+", max "+ + maxSurfacePixelScale[0]+"x"+maxSurfacePixelScale[1]+", req "+ + reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" -> has "+ + hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+"]"); } - protected void runTestGL(final GLCapabilities caps) + protected GLEventListener createDemo(final GLCapabilities caps) { + final GLEventListener demo; + if( 1 == demoType ) { + if( caps.isBitmap() || caps.getGLProfile().isGL2() ) { + final Gears gears = new Gears(swapInterval); + gears.setFlipVerticalInGLOrientation(skipGLOrientationVerticalFlip); + demo = gears; + } else { + final GearsES2 gears = new GearsES2(swapInterval); + gears.setFlipVerticalInGLOrientation(skipGLOrientationVerticalFlip); + demo = gears; + } + } else if( 0 == demoType ) { + demo = new GLClearOnInitReshape(); + } else { + demo = null; + } + return demo; + } + + protected GLJPanel newGLJPanel(final JFrame frame, final GLCapabilities caps, final FPSAnimator animator, final SnapshotGLEventListener snap) throws AWTException, InterruptedException, InvocationTargetException { - System.err.println("Requesting: "+caps); - - final JFrame frame = new JFrame("Swing GLJPanel"); - Assert.assertNotNull(frame); - final GLJPanel glJPanel = new GLJPanel(caps); Assert.assertNotNull(glJPanel); glJPanel.setSkipGLOrientationVerticalFlip(skipGLOrientationVerticalFlip); @@ -136,18 +164,15 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { glJPanel.setPreferredSize(wsize); glJPanel.setSize(wsize); glJPanel.setSurfaceScale(reqSurfacePixelScale); - final float[] valReqSurfacePixelScale = glJPanel.getRequestedSurfaceScale(new float[2]); - if( caps.isBitmap() || caps.getGLProfile().isGL2() ) { - final Gears gears = new Gears(swapInterval); - gears.setFlipVerticalInGLOrientation(skipGLOrientationVerticalFlip); - glJPanel.addGLEventListener(gears); - } else { - final GearsES2 gears = new GearsES2(swapInterval); - gears.setFlipVerticalInGLOrientation(skipGLOrientationVerticalFlip); - glJPanel.addGLEventListener(gears); + { + final GLEventListener demo = createDemo(caps); + if( null != demo ) { + glJPanel.addGLEventListener(demo); + } + } + if( null != snap ) { + glJPanel.addGLEventListener(snap); } - final SnapshotGLEventListener snap = new SnapshotGLEventListener(); - glJPanel.addGLEventListener(snap); glJPanel.addGLEventListener(new GLEventListener() { @Override public void init(final GLAutoDrawable drawable) { } @@ -159,42 +184,128 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { setTitle(frame, glJPanel, caps); } + }); setTitle(frame, glJPanel, caps); - frame.setLocation(xpos, ypos); - final FPSAnimator animator = useAnimator ? new FPSAnimator(glJPanel, 60) : null; + frame.addComponentListener(new ComponentListener() { + @Override + public void componentResized(final ComponentEvent e) { + setTitle(frame, glJPanel, caps); + } + + @Override + public void componentMoved(final ComponentEvent e) { + setTitle(frame, glJPanel, caps); + } - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - frame.getContentPane().add(glJPanel, BorderLayout.CENTER); - frame.getContentPane().validate(); - frame.pack(); - frame.setVisible(true); - } } ) ; - Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); - Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glJPanel, true)); + @Override + public void componentShown(final ComponentEvent e) { } - final Screen screen = NewtFactoryAWT.createScreen(glJPanel, true); - screen.addReference(); // initial native creation - keep alive! - System.err.println("GetPixelScale: AWT -> Screen: "+screen); + @Override + public void componentHidden(final ComponentEvent e) { } + }); - final float[] hasSurfacePixelScale1 = glJPanel.getCurrentSurfaceScale(new float[2]); - System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+ - valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ - hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); - setTitle(frame, glJPanel, caps); + if( SwingUtilities.isEventDispatchThread() ) { + frame.getContentPane().add(glJPanel, BorderLayout.CENTER); + frame.getContentPane().validate(); + frame.pack(); + frame.setVisible(true); + } else { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.getContentPane().add(glJPanel, BorderLayout.CENTER); + frame.getContentPane().validate(); + frame.pack(); + frame.setVisible(true); + } } ) ; + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true)); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glJPanel, true)); + + final float[] minSurfacePixelScale = glJPanel.getMinimumSurfaceScale(new float[2]); + final float[] maxSurfacePixelScale = glJPanel.getMaximumSurfaceScale(new float[2]); + final float[] valReqSurfacePixelScale = glJPanel.getRequestedSurfaceScale(new float[2]); + final float[] hasSurfacePixelScale = glJPanel.getCurrentSurfaceScale(new float[2]); + System.err.println("HiDPI PixelScale: min "+ + minSurfacePixelScale[0]+"x"+minSurfacePixelScale[1]+", max "+ + maxSurfacePixelScale[0]+"x"+maxSurfacePixelScale[1]+", req "+ + reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" -> val "+ + valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" -> has "+ + hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]); + setTitle(frame, glJPanel, caps); + } - if( useAnimator ) { + if( null != animator ) { + animator.add(glJPanel); animator.setUpdateFPSFrames(60, System.err); + } + return glJPanel; + } + + protected void destroy(final JFrame frame, final GLJPanel glJPanel) { + try { + if( SwingUtilities.isEventDispatchThread() ) { + if( null != frame ) { + frame.setVisible(false); + if( null != glJPanel ) { + frame.getContentPane().remove(glJPanel); + } + frame.remove(glJPanel); + } + if( null != glJPanel ) { + glJPanel.destroy(); + } + if( null != frame ) { + frame.dispose(); + } + } else { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + if( null != frame ) { + frame.setVisible(false); + if( null != glJPanel ) { + frame.getContentPane().remove(glJPanel); + } + frame.remove(glJPanel); + } + if( null != glJPanel ) { + glJPanel.destroy(); + } + if( null != frame ) { + frame.dispose(); + } + } } ); + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + + protected void runTestGL(final GLCapabilities caps) + throws AWTException, InterruptedException, InvocationTargetException + { + final JFrame frame = new JFrame("Swing GLJPanel"); + frame.setLocation(xpos, ypos); + Assert.assertNotNull(frame); + + final FPSAnimator animator = useAnimator ? new FPSAnimator(60) : null; + final SnapshotGLEventListener snap = new SnapshotGLEventListener(); + final GLJPanel glJPanel = newGLJPanel(frame, caps, animator, snap); + if( null != animator ) { animator.start(); Assert.assertEquals(true, animator.isAnimating()); } + final Screen screen = NewtFactoryAWT.createScreen(glJPanel, true); + screen.addReference(); // initial native creation - keep alive! + System.err.println("GetPixelScale: AWT -> Screen: "+screen); final QuitAdapter quitAdapter = new QuitAdapter(); new AWTKeyAdapter(new TraceKeyAdapter(quitAdapter), glJPanel).addTo(glJPanel); new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter), glJPanel).addTo(frame); + final JFrame[] frame2 = { null }; + final GLJPanel[] glJPanel2 = { null }; + final com.jogamp.newt.event.KeyListener kl = new com.jogamp.newt.event.KeyAdapter() { @Override public void keyPressed(final KeyEvent e) { @@ -262,6 +373,33 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { glJPanel.setRequestedGLCapabilities(capsNew); System.err.println("XXX-A2: "+animator.toString()); System.err.println("XXX: "+glJPanel.toString()); + } else if(e.getKeyChar()=='n') { + System.err.println("XXX: frame2: "+frame2[0]); + if( null != frame2[0] ) { + System.err.println("XXX: frame2.isShowing: "+frame2[0].isShowing()); + } + System.err.println("XXX: glJPanel2: "+glJPanel2[0]); + if( null != frame2[0] && frame2[0].isShowing() ) { + destroy(frame2[0], glJPanel2[0]); + frame2[0] = null; + glJPanel2[0] = null; + } else { + frame2[0] = new JFrame("GLJPanel2"); + frame2[0].setLocation(frame.getX()+frame.getWidth()+64, frame.getY()); + final FPSAnimator animator2 = useAnimator ? new FPSAnimator(60) : null; + if( null != animator2 ) { + animator2.start(); + } + final SnapshotGLEventListener snap2 = new SnapshotGLEventListener(); + try { + glJPanel2[0] = newGLJPanel(frame2[0], caps, animator2, snap2); + } catch (final Exception e2) { + e2.printStackTrace(); + destroy(frame2[0], glJPanel2[0]); + frame2[0] = null; + glJPanel2[0] = null; + } + } } } }; new AWTKeyAdapter(kl, glJPanel).addTo(glJPanel); @@ -300,15 +438,12 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { } else { Assert.assertNull(animator); } - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - frame.setVisible(false); - frame.getContentPane().remove(glJPanel); - frame.remove(glJPanel); - glJPanel.destroy(); - frame.dispose(); - } } ); + screen.removeReference(); // final native destroy + destroy(frame, glJPanel); + if( null != frame2[0] ) { + destroy(frame2[0], glJPanel2[0]); + } } @Test @@ -528,6 +663,9 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { shallUseBitmap = true; } else if(args[i].equals("-manual")) { manualTest = true; + } else if(args[i].equals("-demo")) { + i++; + demoType = MiscUtils.atoi(args[i], 0); } } wsize = new Dimension(w, h); @@ -547,6 +685,7 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { System.err.println("shallUsePBuffer "+shallUsePBuffer); System.err.println("shallUseBitmap "+shallUseBitmap); System.err.println("manualTest "+manualTest); + System.err.println("demoType "+demoType); org.junit.runner.JUnitCore.main(TestGearsES2GLJPanelAWT.class.getName()); } 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 5ecda9e20..b389c9ac9 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 @@ -28,6 +28,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.newt; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.TraceWindowAdapter; @@ -109,12 +110,12 @@ public class TestElektronenMultipliziererNEWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setFullscreen(!f_glWindow.isFullscreen()); } }.start(); } else if(e.getKeyChar()=='d') { - new Thread() { + new InterruptSource.Thread() { public void run() { f_glWindow.setUndecorated(!f_glWindow.isUndecorated()); } }.start(); 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 d5afdcfda..43417c317 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 @@ -33,34 +33,39 @@ import java.lang.reflect.InvocationTargetException; import com.jogamp.junit.util.JunitTracer; import com.jogamp.newt.Display; -import com.jogamp.newt.Display.PointerIcon; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Screen; import com.jogamp.newt.Window; import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.TraceMouseAdapter; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.newt.util.EDTUtil; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.MiscUtils; -import com.jogamp.opengl.test.junit.util.NEWTDemoListener; import com.jogamp.opengl.test.junit.util.UITestCase; -import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; +import com.jogamp.opengl.test.junit.jogl.demos.GLClearOnInitReshape; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; - +import com.jogamp.opengl.test.junit.jogl.demos.es2.LineSquareXDemoES2; +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.util.Dimension; import com.jogamp.nativewindow.util.Point; import com.jogamp.nativewindow.util.PointImmutable; import com.jogamp.nativewindow.util.DimensionImmutable; +import com.jogamp.opengl.GL; import com.jogamp.opengl.GLAnimatorControl; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLPipelineFactory; import com.jogamp.opengl.GLProfile; import jogamp.newt.DefaultEDTUtil; @@ -72,6 +77,14 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +/** + * <p> + * The demo code uses {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000} and many more, see {@link #main(String[])} + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestGearsES2NEWT extends UITestCase { static int screenIdx = 0; @@ -102,6 +115,10 @@ public class TestGearsES2NEWT extends UITestCase { static boolean forceES3 = false; static boolean forceGL3 = false; static boolean forceGL2 = false; + static boolean forceDebug = false; + static boolean forceTrace = false; + static int demoType = 1; + static boolean traceMouse = false; static boolean manualTest = false; static boolean exclusiveContext = false; static boolean useAnimator = true; @@ -142,10 +159,50 @@ public class TestGearsES2NEWT extends UITestCase { glWindow.setPointerVisible(mouseVisible); glWindow.confinePointer(mouseConfined); - final GearsES2 demo = new GearsES2(swapInterval); - demo.setUseMappedBuffers(useMappedBuffers); - demo.setValidateBuffers(true); - glWindow.addGLEventListener(demo); + final GLEventListener demo; + if( 2 == demoType ) { + final LineSquareXDemoES2 demo2 = new LineSquareXDemoES2(false); + demo = demo2; + } else if( 1 == demoType ) { + final GearsES2 gearsES2 = new GearsES2(swapInterval); + gearsES2.setUseMappedBuffers(useMappedBuffers); + gearsES2.setValidateBuffers(true); + demo = gearsES2; + } else if( 0 == demoType ) { + demo = new GLClearOnInitReshape(); + } else { + demo = null; + } + if( forceDebug || forceTrace ) { + glWindow.addGLEventListener(new GLEventListener() { + @Override + public void init(final GLAutoDrawable drawable) { + GL _gl = drawable.getGL(); + if(forceDebug) { + try { + _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, _gl, null) ); + } catch (final Exception e) {e.printStackTrace();} + } + + if(forceTrace) { + try { + // Trace .. + _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, _gl, new Object[] { System.err } ) ); + } catch (final Exception e) {e.printStackTrace();} + } + } + @Override + public void dispose(final GLAutoDrawable drawable) {} + @Override + public void display(final GLAutoDrawable drawable) {} + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {} + }); + } + + if( null != demo ) { + glWindow.addGLEventListener(demo); + } final SnapshotGLEventListener snap = new SnapshotGLEventListener(); glWindow.addGLEventListener(snap); @@ -172,32 +229,51 @@ public class TestGearsES2NEWT extends UITestCase { animator.setExclusiveContext(exclusiveContext); } - final QuitAdapter quitAdapter = new QuitAdapter(); - //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter)); - //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter)); - glWindow.addKeyListener(quitAdapter); - glWindow.addWindowListener(quitAdapter); - glWindow.addWindowListener(new WindowAdapter() { public void windowResized(final WindowEvent e) { - System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); + System.err.println("window resized: "+glWindow.getBounds()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); NEWTDemoListener.setTitle(glWindow); } public void windowMoved(final WindowEvent e) { - System.err.println("window moved: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); + System.err.println("window moved: "+glWindow.getBounds()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); NEWTDemoListener.setTitle(glWindow); } }); - final PointerIcon[] pointerIcons = NEWTDemoListener.createPointerIcons(glWindow); - if( setPointerIcon ) { - glWindow.setPointerIcon(pointerIcons[0]); - System.err.println("Set PointerIcon: "+glWindow.getPointerIcon()); - } + final GLWindow[] glWindow2 = { null }; - final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow, pointerIcons); + final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow); + newtDemoListener.quitAdapterEnable(true); glWindow.addKeyListener(newtDemoListener); + if( traceMouse ) { + glWindow.addMouseListener(new TraceMouseAdapter()); + } glWindow.addMouseListener(newtDemoListener); + glWindow.addWindowListener(newtDemoListener); + glWindow.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(final KeyEvent e) { + if( e.isAutoRepeat() ) { + return; + } + if(e.getKeyChar()=='n') { + if( null != glWindow2[0] && glWindow2[0].isNativeValid() ) { + glWindow2[0].destroy(); + glWindow2[0] = null; + } else { + glWindow2[0] = GLWindow.create(screen, caps); + glWindow2[0].setTitle("GLWindow2"); + glWindow2[0].setPosition(glWindow.getX()+glWindow.getWidth()+64, glWindow.getY()); + glWindow2[0].setSize(glWindow.getWidth(), glWindow.getHeight()); + glWindow2[0].addGLEventListener(new LineSquareXDemoES2(false)); + final Animator animator2 = useAnimator ? new Animator(glWindow2[0]) : null; + if( null != animator2 ) { + animator2.start(); + } + glWindow2[0].setVisible(true); + } + } + } } ); if( useAnimator ) { animator.add(glWindow); @@ -231,7 +307,7 @@ public class TestGearsES2NEWT extends UITestCase { final EDTUtil edt = ((Window)upstream).getScreen().getDisplay().getEDTUtil(); System.err.println("EDT invokeAndWaitError: edt type "+edt.getClass().getName()); if( edt instanceof DefaultEDTUtil ) { - quitAdapter.doQuit(); + newtDemoListener.doQuit(); ((DefaultEDTUtil)edt).invokeAndWaitError(new Runnable() { public void run() { throw new RuntimeException("XXX Should never ever be seen! - "+Thread.currentThread()); @@ -255,6 +331,8 @@ public class TestGearsES2NEWT extends UITestCase { animator.setUpdateFPSFrames(60, showFPS ? System.err : null); } + System.err.println("Window Current State : "+glWindow.getStateMaskString()); + System.err.println("Window Supported States: "+glWindow.getSupportedStateMaskString()); System.err.println("NW chosen: "+glWindow.getDelegatedWindow().getChosenCapabilities()); System.err.println("GL chosen: "+glWindow.getChosenCapabilities()); System.err.println("window pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", "+glWindow.getInsets()); @@ -277,7 +355,7 @@ public class TestGearsES2NEWT extends UITestCase { final long t0 = System.currentTimeMillis(); long t1 = t0; - while(!quitAdapter.shouldQuit() && t1-t0<duration) { + while(!newtDemoListener.shouldQuit() && t1-t0<duration) { Thread.sleep(100); t1 = System.currentTimeMillis(); if( SysExit.testError == sysExit || SysExit.testExit == sysExit || SysExit.testEDTError == sysExit) { @@ -292,7 +370,7 @@ public class TestGearsES2NEWT extends UITestCase { final EDTUtil edt = glWindow.getScreen().getDisplay().getEDTUtil(); System.err.println("EDT invokeAndWaitError: edt type "+edt.getClass().getName()); if( edt instanceof DefaultEDTUtil ) { - quitAdapter.doQuit(); + newtDemoListener.doQuit(); ((DefaultEDTUtil)edt).invokeAndWaitError(new Runnable() { public void run() { throw new RuntimeException("XXX Should never ever be seen!"); @@ -312,6 +390,10 @@ public class TestGearsES2NEWT extends UITestCase { } Assert.assertEquals(null, glWindow.getExclusiveContextThread()); glWindow.destroy(); + if( null != glWindow2[0] && glWindow2[0].isNativeValid() ) { + glWindow2[0].destroy(); + glWindow2[0] = null; + } if( NativeWindowFactory.isAWTAvailable() ) { Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glWindow, false)); } @@ -426,6 +508,10 @@ public class TestGearsES2NEWT extends UITestCase { forceGL3 = true; } else if(args[i].equals("-gl2")) { forceGL2 = true; + } else if(args[i].equals("-debug")) { + forceDebug = true; + } else if(args[i].equals("-trace")) { + forceTrace = true; } else if(args[i].equals("-mappedBuffers")) { useMappedBuffers = true; } else if(args[i].equals("-wait")) { @@ -476,6 +562,11 @@ public class TestGearsES2NEWT extends UITestCase { sysExit = SysExit.valueOf(args[i]); } else if(args[i].equals("-manual")) { manualTest = true; + } else if(args[i].equals("-demo")) { + i++; + demoType = MiscUtils.atoi(args[i], 0); + } else if(args[i].equals("-traceMouse")) { + traceMouse = true; } } wsize = new Dimension(w, h); @@ -509,11 +600,15 @@ public class TestGearsES2NEWT extends UITestCase { System.err.println("forceES3 "+forceES3); System.err.println("forceGL3 "+forceGL3); System.err.println("forceGL2 "+forceGL2); + System.err.println("forceDebug "+forceDebug); + System.err.println("forceTrace "+forceTrace); System.err.println("swapInterval "+swapInterval); System.err.println("exclusiveContext "+exclusiveContext); System.err.println("useAnimator "+useAnimator); System.err.println("sysExitWithin "+sysExit); System.err.println("mappedBuffers "+useMappedBuffers); + System.err.println("demoType "+demoType); + System.err.println("traceMouse "+traceMouse); if(waitForKey) { JunitTracer.waitForKey("Start"); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java index 39d13f6a3..77c4bf8f3 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java @@ -47,14 +47,15 @@ import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; 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.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.newt.parenting.NewtAWTReparentingKeyAdapter; +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.util.Dimension; @@ -74,6 +75,14 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +/** + * <p> + * The demo code uses {@link NewtReparentingKeyAdapter} including {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000}, and many more, see {@link #main(String[])} + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestGearsES2NewtCanvasAWT extends UITestCase { public enum FrameLayout { None, TextOnBottom, BorderBottom, BorderBottom2, BorderCenter, BorderCenterSurrounded, DoubleBorderCenterSurrounded }; @@ -82,7 +91,7 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase { static int screenIdx = 0; static PointImmutable wpos; static DimensionImmutable wsize, rwsize = null; - static FrameLayout frameLayout = FrameLayout.None; + static FrameLayout frameLayout = FrameLayout.BorderCenterSurrounded; static ResizeBy resizeBy = ResizeBy.Component; static float[] reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; @@ -248,17 +257,21 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase { final GearsES2 demo = new GearsES2(swapInterval); glWindow.addGLEventListener(demo); + final NewtAWTReparentingKeyAdapter newtDemoListener = new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow); + newtDemoListener.quitAdapterEnable(true); + glWindow.addKeyListener(newtDemoListener); + glWindow.addMouseListener(newtDemoListener); + glWindow.addWindowListener(newtDemoListener); + frame.addComponentListener(new ComponentListener() { @Override public void componentResized(final ComponentEvent e) { - NewtAWTReparentingKeyAdapter.setTitle(frame, newtCanvasAWT, glWindow); + newtDemoListener.setTitle(); } - @Override public void componentMoved(final ComponentEvent e) { - NewtAWTReparentingKeyAdapter.setTitle(frame, newtCanvasAWT, glWindow); + newtDemoListener.setTitle(); } - @Override public void componentShown(final ComponentEvent e) { } @@ -272,12 +285,6 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase { animator.setExclusiveContext(exclusiveContext); } - final QuitAdapter quitAdapter = new QuitAdapter(); - //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter)); - //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter)); - glWindow.addKeyListener(quitAdapter); - glWindow.addWindowListener(quitAdapter); - glWindow.addWindowListener(new WindowAdapter() { public void windowResized(final WindowEvent e) { System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); @@ -287,10 +294,6 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase { } }); - final NewtAWTReparentingKeyAdapter newtDemoListener = new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow, quitAdapter); - glWindow.addKeyListener(newtDemoListener); - glWindow.addMouseListener(newtDemoListener); - if( useAnimator ) { animator.add(glWindow); animator.start(); @@ -324,7 +327,7 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase { System.err.println("HiDPI PixelScale: "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+ valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); - NewtAWTReparentingKeyAdapter.setTitle(frame, newtCanvasAWT, glWindow); + newtDemoListener.setTitle(); if( null != rwsize ) { Thread.sleep(500); // 500ms delay @@ -334,7 +337,7 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase { final long t0 = System.currentTimeMillis(); long t1 = t0; - while(!quitAdapter.shouldQuit() && t1-t0<duration) { + while(!newtDemoListener.shouldQuit() && t1-t0<duration) { Thread.sleep(100); t1 = System.currentTimeMillis(); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasSWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasSWT.java index 8dcffc662..ee72e1e6f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasSWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasSWT.java @@ -31,6 +31,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.newt; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import com.jogamp.common.util.InterruptSource; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.event.KeyAdapter; @@ -184,14 +185,12 @@ public class TestGearsES2NewtCanvasSWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); System.err.println("[set fullscreen pre]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); glWindow.setFullscreen(!glWindow.isFullscreen()); System.err.println("[set fullscreen post]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); - glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); } } }); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2SimpleNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2SimpleNEWT.java index d109c56cf..6aebeb91b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2SimpleNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2SimpleNEWT.java @@ -40,14 +40,14 @@ import com.jogamp.newt.Window; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.MiscUtils; -import com.jogamp.opengl.test.junit.util.NEWTDemoListener; import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.PNGPixelRect; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; - +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.util.Dimension; import com.jogamp.nativewindow.util.DimensionImmutable; @@ -61,6 +61,14 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +/** + * <p> + * The demo code uses {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000} and using a translucent window {@code -translucent}. + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestGearsES2SimpleNEWT extends UITestCase { static final DimensionImmutable wsize = new Dimension(800, 600); @@ -118,7 +126,7 @@ public class TestGearsES2SimpleNEWT extends UITestCase { int idx = 0; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/cross-grey-alpha-16x16.png" }, glWindow.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 8, 8); System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); @@ -130,7 +138,7 @@ public class TestGearsES2SimpleNEWT extends UITestCase { idx++; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/pointer-grey-alpha-16x24.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/pointer-grey-alpha-16x24.png" }, glWindow.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); @@ -142,7 +150,7 @@ public class TestGearsES2SimpleNEWT extends UITestCase { idx++; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-red-alpha-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-red-alpha-64x64.png" }, glWindow.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); @@ -154,7 +162,7 @@ public class TestGearsES2SimpleNEWT extends UITestCase { idx++; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-blue-alpha-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-blue-alpha-64x64.png" }, glWindow.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); @@ -166,7 +174,7 @@ public class TestGearsES2SimpleNEWT extends UITestCase { idx++; if( PNGIcon.isAvailable() ) { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "jogamp-pointer-64x64.png" }, glWindow.getClass().getClassLoader(), null); try { final URLConnection urlConn = res.resolve(0); final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NEWT.java index 79c8cb39a..2c5b6028c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NEWT.java @@ -87,15 +87,15 @@ public class TestLandscapeES2NEWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { glWindow.setFullscreen(!glWindow.isFullscreen()); - } }.start(); + } } ); } else if(e.getKeyChar()=='d') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { glWindow.setUndecorated(!glWindow.isUndecorated()); - } }.start(); + } } ); } } }); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NewtCanvasAWT.java index 12ea6dbb3..c5bbecbc7 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NewtCanvasAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NewtCanvasAWT.java @@ -39,13 +39,14 @@ import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; -import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; import com.jogamp.opengl.test.junit.jogl.demos.es2.LandscapeES2; import com.jogamp.opengl.test.junit.newt.parenting.NewtAWTReparentingKeyAdapter; +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; import com.jogamp.nativewindow.util.Dimension; import com.jogamp.nativewindow.util.DimensionImmutable; @@ -58,6 +59,14 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +/** + * <p> + * The demo code uses {@link NewtReparentingKeyAdapter} including {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000}, and many more, see {@link #main(String[])} + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestLandscapeES2NewtCanvasAWT extends UITestCase { static DimensionImmutable wsize = new Dimension(500, 290); @@ -104,12 +113,6 @@ public class TestLandscapeES2NewtCanvasAWT extends UITestCase { animator.setExclusiveContext(exclusiveContext); } - final QuitAdapter quitAdapter = new QuitAdapter(); - //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter)); - //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter)); - glWindow.addKeyListener(quitAdapter); - glWindow.addWindowListener(quitAdapter); - glWindow.addWindowListener(new WindowAdapter() { public void windowResized(final WindowEvent e) { System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()); @@ -119,7 +122,11 @@ public class TestLandscapeES2NewtCanvasAWT extends UITestCase { } }); - glWindow.addKeyListener(new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow, quitAdapter)); + final NewtReparentingKeyAdapter newtDemoListener = new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow); + newtDemoListener.quitAdapterEnable(true); + glWindow.addKeyListener(newtDemoListener); + glWindow.addMouseListener(newtDemoListener); + glWindow.addWindowListener(newtDemoListener); if( useAnimator ) { animator.add(glWindow); @@ -143,7 +150,7 @@ public class TestLandscapeES2NewtCanvasAWT extends UITestCase { final long t0 = System.currentTimeMillis(); long t1 = t0; - while(!quitAdapter.shouldQuit() && t1-t0<duration) { + while(!newtDemoListener.shouldQuit() && t1-t0<duration) { Thread.sleep(100); t1 = System.currentTimeMillis(); } 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 e8e3741aa..976025c14 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 @@ -110,15 +110,15 @@ public class TestRedSquareES2NEWT extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { glWindow.setFullscreen(!glWindow.isFullscreen()); - } }.start(); + } } ); } else if(e.getKeyChar()=='d') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { glWindow.setUndecorated(!glWindow.isUndecorated()); - } }.start(); + } } ); } } }); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java index c2761f694..a144ff1ff 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java @@ -230,9 +230,7 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { if( !isInit ) { return; } final GL2 gl = glad.getGL().getGL2(); - if(-1 != swapInterval) { - gl.setSwapInterval(swapInterval); - } + gl.setSwapInterval(swapInterval); reshape(gl, x, y, width, height, width, height); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Teapot.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Teapot.java index 22d24b67b..159fad9da 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Teapot.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Teapot.java @@ -72,7 +72,7 @@ public class Teapot implements GLEventListener { gl.glClearColor(0.5f, 0.5f, 0.5f, 0.0f); try { - final URLConnection urlConn = IOUtil.getResource(PNGTstFiles.class, "test-ntscP_3-01-160x90.png"); + final URLConnection urlConn = IOUtil.getResource("test-ntscP_3-01-160x90.png", PNGTstFiles.class.getClassLoader(), PNGTstFiles.class); tex = TextureIO.newTexture(gl, TextureIO.newTextureData(gl.getGLProfile(), urlConn.getInputStream(), false, TextureIO.PNG)); } catch (final Exception e) { e.printStackTrace(); 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 0f3011c3d..0ab9308c2 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 @@ -28,16 +28,15 @@ package com.jogamp.opengl.test.junit.jogl.demos.gl2.newt; -import com.jogamp.newt.event.KeyAdapter; -import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; - +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLProfile; @@ -48,6 +47,14 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +/** + * <p> + * The demo code uses {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000}. + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestGearsNEWT extends UITestCase { static GLProfile glp; @@ -84,25 +91,9 @@ public class TestGearsNEWT extends UITestCase { glWindow.addKeyListener(quitAdapter); glWindow.addWindowListener(quitAdapter); - final GLWindow f_glWindow = glWindow; - glWindow.addKeyListener(new KeyAdapter() { - public void keyReleased(final KeyEvent e) { - if( !e.isPrintableKey() || e.isAutoRepeat() ) { - return; - } - if(e.getKeyChar()=='f') { - new Thread() { - public void run() { - f_glWindow.setFullscreen(!f_glWindow.isFullscreen()); - } }.start(); - } else if(e.getKeyChar()=='d') { - new Thread() { - public void run() { - f_glWindow.setUndecorated(!f_glWindow.isUndecorated()); - } }.start(); - } - } - }); + final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow); + glWindow.addKeyListener(newtDemoListener); + glWindow.addMouseListener(newtDemoListener); glWindow.setSize(width, height); glWindow.setVisible(true); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl3/GeomShader01TextureGL3.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl3/GeomShader01TextureGL3.java index a4a665e5b..668d8877c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl3/GeomShader01TextureGL3.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl3/GeomShader01TextureGL3.java @@ -193,7 +193,7 @@ public class GeomShader01TextureGL3 implements GLEventListener { } private Texture createTestTexture(final GL3 gl) throws IOException { - final URLConnection urlConn = IOUtil.getResource(this.getClass(), "../../util/texture/test-ntscN_3-01-160x90.png"); + final URLConnection urlConn = IOUtil.getResource("../../util/texture/test-ntscN_3-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); if(null == urlConn) { return null; } final InputStream istream = urlConn.getInputStream(); if(null == istream) { return null; } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/javafx/PureJFXApp01.java b/src/test/com/jogamp/opengl/test/junit/jogl/javafx/PureJFXApp01.java new file mode 100644 index 000000000..d2a3b8073 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/javafx/PureJFXApp01.java @@ -0,0 +1,54 @@ +/** + * Copyright 2019 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.javafx; + +import javafx.application.Application; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.text.Font; +import javafx.scene.text.Text; +import javafx.stage.Stage; + +public class PureJFXApp01 extends Application { + + @Override public void start(Stage stage) { + Text text = new Text(10, 40, "Pure JFX App 01"); + text.setFont(new Font(40)); + Scene scene = new Scene(new Group(text)); + + stage.setTitle("JavaFX Stage"); + stage.setScene(scene); + stage.sizeToScene(); + stage.show(); + } + + public static void main(String[] args) { + Application.launch(args); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/javafx/TestNewtCanvasJFXGLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/javafx/TestNewtCanvasJFXGLn.java new file mode 100644 index 000000000..27ce49af4 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/javafx/TestNewtCanvasJFXGLn.java @@ -0,0 +1,516 @@ +/** + * Copyright 2019 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.javafx; + +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import com.jogamp.common.util.RunnableTask; +import com.jogamp.nativewindow.javafx.JFXAccessor; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.javafx.NewtCanvasJFX; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.jogl.demos.es2.MultisampleDemoES2; +import com.jogamp.opengl.test.junit.newt.parenting.NewtJFXReparentingKeyAdapter; +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; +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; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.texture.TextureIO; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.Text; +import javafx.stage.Stage; + +/** + * {@link NewtCanvasJFX} basic functional integration test + * of its native parented NEWT child {@link GLWindow} attached to JavaFX's {@link Canvas}. + * <p> + * {@link NewtCanvasJFX} allows utilizing custom {@link GLCapabilities} settings independent from the JavaFX's window + * as well as independent rendering from JavaFX's thread. + * </p> + * <p> + * This unit tests also tests {@link NewtCanvasJFX} native parenting operations before and after + * it's belonging Group's Scene has been attached to the JavaFX {@link javafx.stage.Window Window}'s actual native window, + * i.e. becoming fully realized and visible. + * </p> + * <p> + * Note that {@link JFXAccessor#runOnJFXThread(boolean, Runnable)} is still used to for certain + * mandatory JavaFX lifecycle operation on the JavaFX thread. + * </p> + * <p> + * The demo code uses {@link NewtReparentingKeyAdapter} including {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows running a single test, e.g. {@code -test 21}, and setting each tests's duration in milliseconds, e.g.{@code -time 10000}. + * </p> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestNewtCanvasJFXGLn extends UITestCase { + + static int duration = 5000; // 250; + static int manualTestID = -1; + + com.jogamp.newt.Display jfxNewtDisplay = null; + + public static class JFXApp extends Application { + static Stage stage; + + final static Object sync = new Object(); + static volatile boolean isLaunched = false; + + public JFXApp() { + } + + @Override public void init() throws Exception { + // pre JFX thread + System.err.println("JFX init ...: "+Thread.currentThread()); + } + + @Override public void start(final Stage stage) { + System.err.println("JFX start.0 ...: "+Thread.currentThread()); + synchronized(sync) { + try { + // on JFX thread + final Scene scene = new Scene(new Group(), defWidth, defHeight); + stage.setTitle(TestNewtCanvasJFXGLn.class.getSimpleName()); + stage.setScene(scene); + stage.sizeToScene(); + { + final long h = JFXAccessor.getWindowHandle(stage); + System.err.println("t1 - Native window: 0x"+Long.toHexString(h)); + } + stage.show(); + { + final long h = JFXAccessor.getWindowHandle(stage); + System.err.println("t2 - Native window: 0x"+Long.toHexString(h)); + } + JFXApp.stage = stage; + } finally { + isLaunched = true; + sync.notifyAll(); + } + } + System.err.println("JFX start.X ...: "+Thread.currentThread()); + } + @Override public void stop() throws Exception { + System.err.println("JFX stop ...: "+Thread.currentThread()); + } + public static void startup() throws InterruptedException { + System.out.println( "GLProfile " + GLProfile.glAvailabilityToString() ); + System.err.println("JFX Available: "+JFXAccessor.isJFXAvailable()); + if( JFXAccessor.isJFXAvailable() ) { + Platform.setImplicitExit(false); // FIXME: Default for all NEWT cases? + synchronized(sync) { + final Thread ct = Thread.currentThread(); + RunnableTask.invokeOnNewThread(ct.getThreadGroup(), ct.getName()+"JFXLauncher", false, + new Runnable() { + public void run() { + Application.launch(JFXApp.class); + } + }); + while(!isLaunched) { + sync.wait(); + } + } + System.err.println("JFX launched ..."); + } + } + public static void shutdown() { + JFXAccessor.runOnJFXThread(true, new Runnable() { + public void run() { + if( null != stage ) { + stage.close(); + } + } }); + } + } + + @BeforeClass + public static void startup() throws InterruptedException { + JFXApp.startup(); + } + + @AfterClass + public static void shutdown() { + JFXApp.shutdown(); + Platform.exit(); + } + + @Before + public void init() { + jfxNewtDisplay = NewtFactory.createDisplay(null, false); // no-reuse + } + + @After + public void release() { + jfxNewtDisplay = null; + } + + class WaitAction implements Runnable { + private final long sleepMS; + + WaitAction(final long sleepMS) { + this.sleepMS = sleepMS; + } + public void run() { + // blocks on linux .. display.sleep(); + try { + Thread.sleep(sleepMS); + } catch (final InterruptedException e) { } + } + } + final WaitAction awtRobotWaitAction = new WaitAction(AWTRobotUtil.TIME_SLICE); + final WaitAction generalWaitAction = new WaitAction(10); + + static final int defWidth = 800, defHeight = 600; + + static void populateScene(final Scene scene, final boolean postAttach, + final GLWindow glWindow, + final int width, final int height, final boolean useBorder, + final NewtCanvasJFX[] res) { + final javafx.stage.Window w = scene.getWindow(); + final boolean isShowing = null != w && w.isShowing(); + final Group g = new Group(); + + final int cx, cy, cw, ch, bw, bh; + if( useBorder ) { + bw = width/5; bh = height/5; + cx = bw; cy = bh; cw = width-bw-bw; ch = height-bh-bh; + } else { + bw = 0; bh = 0; + cx = 0; cy = 0; cw = width; ch = height; + } + System.err.println("Scene "+width+"x"+height+", isShowing "+isShowing+", postAttach "+postAttach); + System.err.println("Scene.canvas "+cx+"/"+cy+" "+cw+"x"+ch); + System.err.println("Scene.border "+bw+"x"+bh); + + if( !postAttach ) { + if(isShowing) { + JFXAccessor.runOnJFXThread(true, new Runnable() { + @Override + public void run() { + scene.setRoot(g); + }}); + } else { + scene.setRoot(g); + } + } + + final Canvas canvas0; + if( null == res ) { + canvas0 = new Canvas(); + } else { + res[0] = new NewtCanvasJFX( glWindow ); + canvas0 = res[0]; + } + canvas0.setWidth(cw); + canvas0.setHeight(ch); + if( null == res ) { + final GraphicsContext gc = canvas0.getGraphicsContext2D(); + gc.setFill(Color.BLUE); + gc.fillRect(0, 0, cw, ch); + } + canvas0.relocate(cx, cy); + + final Text text0 = new Text(0, 0, "left"); + { + text0.setFont(new Font(40)); + text0.relocate(0, height/2); + } + final Text text1 = new Text(0, 0, "above"); + { + text1.setFont(new Font(40)); + text1.relocate(width/2, bh-40); + } + final Text text2 = new Text(0, 0, "right"); + { + text2.setFont(new Font(40)); + text2.relocate(width-bw, height/2); + } + final Text text3 = new Text(0, 0, "below"); + { + text3.setFont(new Font(40)); + text3.relocate(width/2, height-bh); + } + final Runnable attach2Group = new Runnable() { + @Override + public void run() { + g.getChildren().add(text0); + g.getChildren().add(text1); + g.getChildren().add(canvas0); + g.getChildren().add(text2); + g.getChildren().add(text3); + } }; + if( !postAttach && isShowing ) { + JFXAccessor.runOnJFXThread(true, attach2Group); + } else { + attach2Group.run(); + } + if( postAttach ) { + if(isShowing) { + JFXAccessor.runOnJFXThread(true, new Runnable() { + @Override + public void run() { + scene.setRoot(g); + }}); + } else { + scene.setRoot(g); + } + } + } + + protected void runTestAGL( final GLCapabilitiesImmutable caps, final GLEventListener demo, + final boolean postAttachNewtCanvas, final boolean postAttachGLWindow, + final boolean useAnimator ) throws InterruptedException { + if( !JFXAccessor.isJFXAvailable() ) { + System.err.println("JFX not available"); + return; + } + final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false); + final GLWindow glWindow1; + if( null == demo ) { + glWindow1 = null; + } else { + final Screen screen = NewtFactory.createScreen(jfxNewtDisplay, 0); + glWindow1 = GLWindow.create(screen, caps); + Assert.assertNotNull(glWindow1); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeValid()); + Assert.assertNull(glWindow1.getParent()); + glWindow1.addGLEventListener(demo); + glWindow1.addGLEventListener(new GLEventListener() { + int displayCount = 0; + public void init(final GLAutoDrawable drawable) { } + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { } + public void display(final GLAutoDrawable drawable) { + if(displayCount < 3) { + snapshot(displayCount++, null, drawable.getGL(), screenshot, TextureIO.PNG, null); + } + } + public void dispose(final GLAutoDrawable drawable) { } + }); + } + + final NewtCanvasJFX[] glCanvas = null==demo? null : new NewtCanvasJFX[]{null}; + + final Scene scene = new Scene(new Group(), defWidth, defHeight); + if(!postAttachNewtCanvas) { + System.err.println("Stage set.A0"); + JFXAccessor.runOnJFXThread(true, new Runnable() { + public void run() { + System.err.println("Stage set.A1"); + JFXApp.stage.setScene(scene); + JFXApp.stage.sizeToScene(); + System.err.println("Stage set.AX"); + } }); + } + populateScene( scene, postAttachNewtCanvas, postAttachGLWindow?null:glWindow1, defWidth, defHeight, true, glCanvas); + if(postAttachNewtCanvas) { + System.err.println("Stage set.B0"); + JFXAccessor.runOnJFXThread(true, new Runnable() { + public void run() { + System.err.println("Stage set.B1"); + JFXApp.stage.setScene(scene); + JFXApp.stage.sizeToScene(); + System.err.println("Stage set.BX"); + } }); + } + + if(postAttachGLWindow && null != demo) { + glCanvas[0].setNEWTChild(glWindow1); + } + + if( null != glWindow1 ) { + Assert.assertTrue("GLWindow didn't become visible natively!", AWTRobotUtil.waitForRealized(glWindow1, awtRobotWaitAction, true)); + System.err.println("GLWindow LOS.0: "+glWindow1.getLocationOnScreen(null)); + glWindow1.addWindowListener(new WindowAdapter() { + public void windowResized(final WindowEvent e) { + System.err.println("window resized: "+glWindow1.getX()+"/"+glWindow1.getY()+" "+glWindow1.getSurfaceWidth()+"x"+glWindow1.getSurfaceHeight()); + } + public void windowMoved(final WindowEvent e) { + System.err.println("window moved: "+glWindow1.getX()+"/"+glWindow1.getY()+" "+glWindow1.getSurfaceWidth()+"x"+glWindow1.getSurfaceHeight()); + } + }); + final NewtReparentingKeyAdapter newtDemoListener = new NewtJFXReparentingKeyAdapter(JFXApp.stage, glCanvas[0], glWindow1); + newtDemoListener.quitAdapterEnable(true); + glWindow1.addKeyListener(newtDemoListener); + glWindow1.addMouseListener(newtDemoListener); + glWindow1.addWindowListener(newtDemoListener); + + final ChangeListener<Number> sizeListener = new ChangeListener<Number>() { + @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { + newtDemoListener.setTitle(); + } }; + JFXApp.stage.widthProperty().addListener(sizeListener); + JFXApp.stage.heightProperty().addListener(sizeListener); + + } + if( null != demo ) { + System.err.println("NewtCanvasJFX LOS.0: "+glCanvas[0].getNativeWindow().getLocationOnScreen(null)); + } + + Animator anim; + if(useAnimator && null != demo) { + anim = new Animator(glWindow1); + anim.start(); + } else { + anim = null; + } + + final long lStartTime = System.currentTimeMillis(); + final long lEndTime = lStartTime + duration; + try { + while( (System.currentTimeMillis() < lEndTime) ) { + generalWaitAction.run(); + } + } catch( final Throwable throwable ) { + throwable.printStackTrace(); + Assume.assumeNoException( throwable ); + } + if(null != anim) { + anim.stop(); + } + + JFXAccessor.runOnJFXThread(true, new Runnable() { + public void run() { + populateScene( JFXApp.stage.getScene(), false, null, defWidth, defHeight, true, null); + JFXApp.stage.sizeToScene(); + } }); + } + + @Test + public void test00() throws InterruptedException { + if( 0 > manualTestID || 0 == manualTestID ) { + runTestAGL( null, null, + false /* postAttachNewtCanvas */, false /* postAttach */, false /* animator */); + } + } + + @Test + public void test11_preAttachNewtGL_NoAnim() throws InterruptedException { + if( 0 > manualTestID || 11 == manualTestID ) { + runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2(), + false /* postAttachNewtCanvas */, false /* postAttachGLWindow */, false /* animator */); + } + } + + @Test + public void test12_postAttachNewt_NoAnim() throws InterruptedException { + if( 0 > manualTestID || 12 == manualTestID ) { + runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2(), + true /* postAttachNewtCanvas */, false /* postAttachGLWindow */, false /* animator */); + } + } + + @Test + public void test13_postAttachGL_NoAnim() throws InterruptedException { + if( 0 > manualTestID || 13 == manualTestID ) { + runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2(), + false /* postAttachNewtCanvas */, true /* postAttachGLWindow */, false /* animator */); + } + } + + @Test + public void test14_postAttachNewtGL_NoAnim() throws InterruptedException { + if( 0 > manualTestID || 14 == manualTestID ) { + runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2(), + true /* postAttachNewtCanvas */, true /* postAttachGLWindow */, false /* animator */); + } + } + + @Test + public void test21_preAttachNewtGL_DoAnim() throws InterruptedException { + if( 0 > manualTestID || 21 == manualTestID ) { + runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2(), + false /* postAttachNewtCanvas */, false /* postAttachGLWindow */, true /* animator */); + } + } + + @Test + public void test22_postAttachNewt_DoAnim() throws InterruptedException { + if( 0 > manualTestID || 22 == manualTestID ) { + runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2(), + true /* postAttachNewtCanvas */, false /* postAttachGLWindow */, true /* animator */); + } + } + + @Test + public void test30_MultisampleAndAlpha() throws InterruptedException { + if( 0 > manualTestID || 30 == manualTestID ) { + final GLCapabilities caps = new GLCapabilities(GLProfile.getGL2ES2()); + caps.setSampleBuffers(true); + caps.setNumSamples(2); + runTestAGL( caps, new MultisampleDemoES2(true), + false /* postAttachNewtCanvas */, false /* postAttachGLWindow */, false /* animator */); + } + } + + public static void main(final String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + duration = MiscUtils.atoi(args[++i], duration); + } + if(args[i].equals("-test")) { + manualTestID = MiscUtils.atoi(args[++i], -1); + } + } + System.out.println("durationPerTest: "+duration+", test "+manualTestID); + org.junit.runner.JUnitCore.main(TestNewtCanvasJFXGLn.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix01NEWT.java index 1e65b15bc..04413315a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix01NEWT.java @@ -47,7 +47,6 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; -import com.jogamp.common.os.Platform; import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.geom.Frustum; import com.jogamp.opengl.test.junit.util.MiscUtils; @@ -102,6 +101,7 @@ public class TestPMVMatrix01NEWT extends UITestCase { 0.0f, 0.0f, 0.0f, 1.0f } ); @Test + @SuppressWarnings("deprecation") public void test00MatrixToString() { final String s4x4Cpmv = PMVMatrix.matrixToString(null, "%10.5f", translated123C).toString(); final String s4x4Cflu = FloatUtil.matrixToString(null, null, "%10.5f", translated123C, 0, 4, 4, false).toString(); @@ -328,7 +328,6 @@ public class TestPMVMatrix01NEWT extends UITestCase { // System.err.println("P2: "+pmv.toString()); } - @SuppressWarnings("unused") @Test public void test03MvTranslate() { final FloatBuffer pmvMv; @@ -367,7 +366,6 @@ public class TestPMVMatrix01NEWT extends UITestCase { // System.err.println("pmvMvit: "+Platform.NEWLINE+PMVMatrix.matrixToString(null, "%10.5f", pmvMvit)); } - @SuppressWarnings("unused") @Test public void test04MvTranslateRotate() { final FloatBuffer pmvMv; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashForm.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashForm.java index aec728cad..eec31b064 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashForm.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashForm.java @@ -198,14 +198,14 @@ public class TestBug672NewtCanvasSWTSashForm extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { final Thread t = glWindow.setExclusiveContextThread(null); System.err.println("[set fullscreen pre]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); glWindow.setFullscreen(!glWindow.isFullscreen()); System.err.println("[set fullscreen post]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); } } }); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashFormComposite.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashFormComposite.java index 0578492e2..fdd6d6458 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashFormComposite.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestBug672NewtCanvasSWTSashFormComposite.java @@ -205,14 +205,14 @@ public class TestBug672NewtCanvasSWTSashFormComposite extends UITestCase { return; } if(e.getKeyChar()=='f') { - new Thread() { + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { final Thread t = glWindow.setExclusiveContextThread(null); System.err.println("[set fullscreen pre]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); glWindow.setFullscreen(!glWindow.isFullscreen()); System.err.println("[set fullscreen post]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()); glWindow.setExclusiveContextThread(t); - } }.start(); + } } ); } } }); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlockAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlockAWT.java index 9a422f411..22053483e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlockAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlockAWT.java @@ -50,7 +50,8 @@ import com.jogamp.opengl.GLCapabilities ; import com.jogamp.opengl.GLEventListener ; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; - +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.InterruptedRuntimeException; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.event.KeyAdapter; @@ -143,14 +144,13 @@ public class TestNewtCanvasSWTBug628ResizeDeadlockAWT extends UITestCase { //////////////////////////////////////////////////////////////////////////////// - static class ResizeThread extends Thread { + static class ResizeThread extends InterruptSource.Thread { volatile boolean shallStop = false; private final Shell _shell ; private int _n ; public ResizeThread( final Shell shell ) { - super(); _shell = shell ; } @@ -196,9 +196,9 @@ public class TestNewtCanvasSWTBug628ResizeDeadlockAWT extends UITestCase { display.asyncExec( resizeAction ); display.wake(); - Thread.sleep( 50L ) ; + java.lang.Thread.sleep( 50L ) ; } catch( final InterruptedException e ) { - break ; + throw new InterruptedRuntimeException(e); } } System.err.println("*R-Exit* shallStop "+shallStop+", disposed "+_shell.isDisposed()); @@ -207,7 +207,7 @@ public class TestNewtCanvasSWTBug628ResizeDeadlockAWT extends UITestCase { //////////////////////////////////////////////////////////////////////////////// - static class KeyfireThread extends Thread + static class KeyfireThread extends InterruptSource.Thread { volatile boolean shallStop = false; Display _display; @@ -216,6 +216,7 @@ public class TestNewtCanvasSWTBug628ResizeDeadlockAWT extends UITestCase { public KeyfireThread(final Robot robot, final Display display) { + super(); _robot = robot; _display = display; } @@ -231,7 +232,7 @@ public class TestNewtCanvasSWTBug628ResizeDeadlockAWT extends UITestCase { AWTRobotUtil.waitForIdle(_robot); AWTRobotUtil.newtKeyPress(_n, _robot, true, KeyEvent.VK_0, 10); AWTRobotUtil.newtKeyPress(_n, _robot, false, KeyEvent.VK_0, 0); - Thread.sleep( 40L ) ; + java.lang.Thread.sleep( 40L ) ; _n++; if(!_display.isDisposed()) { _display.wake(); @@ -368,7 +369,7 @@ public class TestNewtCanvasSWTBug628ResizeDeadlockAWT extends UITestCase { } { - final Thread t = new Thread(new Runnable() { + final Thread t = new InterruptSource.Thread(null, new Runnable() { @Override public void run() { try { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java index 7072ed9ea..9b2e46d44 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java @@ -51,6 +51,7 @@ import com.jogamp.opengl.GLProfile; import jogamp.newt.swt.SWTEDTUtil; import jogamp.newt.swt.event.SWTNewtEventFactory; +import com.jogamp.common.util.InterruptSource; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.opengl.GLWindow ; @@ -110,7 +111,7 @@ public class TestSWTBug643AsyncExec extends UITestCase { //////////////////////////////////////////////////////////////////////////////// - static class AsyncExecEDTFeederThread extends Thread { + static class AsyncExecEDTFeederThread extends InterruptSource.Thread { volatile boolean shallStop = false; private final Display swtDisplay ; private final jogamp.newt.DisplayImpl newtDisplay; @@ -118,7 +119,6 @@ public class TestSWTBug643AsyncExec extends UITestCase { public AsyncExecEDTFeederThread( final Display swtDisplay, final com.jogamp.newt.Display newtDisplay ) { - super(); this.swtDisplay = swtDisplay ; this.newtDisplay = (jogamp.newt.DisplayImpl)newtDisplay; } @@ -152,7 +152,7 @@ public class TestSWTBug643AsyncExec extends UITestCase { // only perform async exec on valid and already running NEWT EDT! newtDisplay.runOnEDTIfAvail(false, newtAsyncAction); } - Thread.sleep( 50L ) ; + java.lang.Thread.sleep( 50L ) ; } catch( final InterruptedException e ) { break ; } @@ -275,7 +275,7 @@ public class TestSWTBug643AsyncExec extends UITestCase { } { - final Thread t = new Thread(new Runnable() { + final Thread t = new InterruptSource.Thread(null, new Runnable() { @Override public void run() { try { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/DemoGL2ES1TextureImmModeSink.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/DemoGL2ES1TextureImmModeSink.java index f90b32009..572871233 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/DemoGL2ES1TextureImmModeSink.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/DemoGL2ES1TextureImmModeSink.java @@ -97,7 +97,7 @@ public class DemoGL2ES1TextureImmModeSink implements GLEventListener, TextureDra } final GL2ES1 gl = FixedFuncUtil.wrapFixedFuncEmul(_gl, ShaderSelectionMode.AUTO, null, forceFFPEmu, verboseFFPEmu); - final URLConnection testTextureUrlConn = IOUtil.getResource(PNGTstFiles.class, "test-ntscP_3-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscP_3-01-160x90.png", PNGTstFiles.class.getClassLoader(), PNGTstFiles.class); try { final InputStream testTextureStream = testTextureUrlConn.getInputStream(); textureData = TextureIO.newTextureData(gl.getGLProfile(), testTextureStream , false /* mipmap */, TextureIO.PNG); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/ImageTstFiles.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/ImageTstFiles.java new file mode 100644 index 000000000..25bb7e788 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/ImageTstFiles.java @@ -0,0 +1,128 @@ +/** + * Copyright 2014 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.util.texture; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URLConnection; +import java.util.ArrayList; + +import com.jogamp.common.util.IOUtil; + +public class ImageTstFiles { + public static final String[] pngFileNames = new String[] { + "bug724-transparent-grey_gimpexp.png", + "bug724-transparent-grey_orig.png", + "cross-grey-alpha-16x16.png", + "grayscale_texture.png", + "pointer-grey-alpha-16x24.png", + "test-ntscI_3-01-160x90.png", + "test-ntscI_4-01-160x90.png", + "test-ntscIG3-01-160x90.png", + "test-ntscIG4-01-160x90.png", + "test-ntscN_3-01-160x90.png", + "test-ntscN_4-01-160x90.png", + "test-ntscNG4-01-160x90.png", + "test-ntscP_3-01-160x90.png", + "test-ntscP_4-01-160x90.png" + }; + + public static final String[] jpgFileNames = new String[] { + "bug745_qttdef_post_frame.jpg", + "darwin_03_N_4-YCCK-640x452.jpg", // local + "darwin_03_N_4-YCCK.jpg", // local + "j1-baseline.jpg", + "j2-progressive.jpg", + "j3-baseline_gray.jpg", + "test-cmyk-01.jpg", + "test-ntscN_3-01-160x90-60pct-yuv422h-base.jpg", + "test-ntscN_3-01-160x90-60pct-yuv422h-prog.jpg", + "test-ntscN_3-01-160x90-90pct-yuv444-base.jpg", + "test-ntscN_3-01-160x90-90pct-yuv444-prog.jpg", + "test-ycck-01.jpg" }; + + public static final String[] tgaFileNames = new String[] { + "bug744-rle32.tga", + "bug982.rle32.256x256.tga", + "test-u32.tga" + }; + public static final String[] ddsFileNames = new String[] { + "test-64x32_DXT1.dds", + "test-64x32_DXT5.dds", + "test-64x32_uncompressed.dds" + }; + + public static class NamedInputStream { + final String fullPath; + final String basePath; + final InputStream stream; + public NamedInputStream(final String fullPath, final String basePath, final InputStream stream) { + this.fullPath = fullPath; + this.basePath = basePath; + this.stream = stream; + } + } + public ArrayList<NamedInputStream> pngStreams; + public ArrayList<NamedInputStream> jpgStreams; + public ArrayList<NamedInputStream> tgaStreams; + public ArrayList<NamedInputStream> ddsStreams; + public ArrayList<NamedInputStream> allStreams; + + private final ArrayList<NamedInputStream> init(final String[] source) throws IOException { + final ArrayList<NamedInputStream> sink = new ArrayList<NamedInputStream>(); + for(int i=0; i<source.length; i++) { + final URLConnection testTextureUrlConn = IOUtil.getResource(source[i], this.getClass().getClassLoader(), this.getClass()); + if( null != testTextureUrlConn ) { + final InputStream s = testTextureUrlConn.getInputStream(); + if( null != s ) { + sink.add(new NamedInputStream(testTextureUrlConn.getURL().toString(), source[i], s)); + } + } + } + return sink; + } + + public void init() throws IOException { + pngStreams = init(pngFileNames); + jpgStreams = init(jpgFileNames); + tgaStreams = init(tgaFileNames); + ddsStreams = init(ddsFileNames); + allStreams = new ArrayList<NamedInputStream>(); + allStreams.addAll(pngStreams); + allStreams.addAll(jpgStreams); + allStreams.addAll(tgaStreams); + allStreams.addAll(ddsStreams); + } + public void clear() { + pngStreams.clear(); + jpgStreams.clear(); + tgaStreams.clear(); + ddsStreams.clear(); + allStreams.clear(); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug362DDSImageCreateFromData.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug362DDSImageCreateFromData.java index a585e9eaf..71233d07c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug362DDSImageCreateFromData.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug362DDSImageCreateFromData.java @@ -56,7 +56,7 @@ public class TestBug362DDSImageCreateFromData { } private File initFile(final String filename) throws URISyntaxException { - final URLConnection connection = IOUtil.getResource(getClass(), filename); + final URLConnection connection = IOUtil.getResource(filename, getClass().getClassLoader(), getClass()); Assert.assertNotNull(connection); final URL url = connection.getURL(); final File file = new File(url.toURI()); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestGLReadBufferUtilTextureIOWrite02NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestGLReadBufferUtilTextureIOWrite02NEWT.java index 8339831a0..7fc14a609 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestGLReadBufferUtilTextureIOWrite02NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestGLReadBufferUtilTextureIOWrite02NEWT.java @@ -28,6 +28,7 @@ package com.jogamp.opengl.test.junit.jogl.util.texture; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.GLAutoDrawable; @@ -99,7 +100,7 @@ public class TestGLReadBufferUtilTextureIOWrite02NEWT extends UITestCase { c=0; snapshot(i++, null, drawable.getGL(), screenshot, TextureIO.PNG, null); dw_old = dw; - new Thread() { + new InterruptSource.Thread() { @Override public void run() { glWindow.setSize(2*dw, 2*dh); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestImageTypeNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestImageTypeNEWT.java new file mode 100644 index 000000000..952d54443 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestImageTypeNEWT.java @@ -0,0 +1,92 @@ +/** + * Copyright 2015 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.util.texture; + +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.texture.ImageType; + +import java.io.IOException; +import java.util.List; + +import org.junit.Assert; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestImageTypeNEWT extends UITestCase { + ImageTstFiles imageTstFiles; + + @Before + public void initTest() throws IOException { + imageTstFiles = new ImageTstFiles(); + imageTstFiles.init(); + } + + @After + public void cleanupTest() { + imageTstFiles.clear(); + } + + public void testImpl(final List<ImageTstFiles.NamedInputStream> streams, final ImageType expImageType) throws InterruptedException, IOException { + for(int i=0; i<streams.size(); i++) { + final ImageTstFiles.NamedInputStream s = streams.get(i); + final ImageType t = new ImageType(s.stream); + System.err.printf("Test %3d: path %s, exp-type %s, has-type %s%n", i, s.basePath, expImageType, t); + Assert.assertEquals(expImageType, t); + } + } + + @Test + public void test01AllPNG() throws InterruptedException, IOException { + testImpl(imageTstFiles.pngStreams, new ImageType(ImageType.T_PNG)); + } + + @Test + public void test02AllJPG() throws InterruptedException, IOException { + testImpl(imageTstFiles.jpgStreams, new ImageType(ImageType.T_JPG)); + } + + // TGA cannot be detected + // @Test + public void test03AllTGA() throws InterruptedException, IOException { + testImpl(imageTstFiles.tgaStreams, new ImageType(ImageType.T_TGA)); + } + + @Test + public void test04AllDDS() throws InterruptedException, IOException { + testImpl(imageTstFiles.ddsStreams, new ImageType(ImageType.T_DDS)); + } + + public static void main(final String args[]) throws IOException { + org.junit.runner.JUnitCore.main(TestImageTypeNEWT.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGImage01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGImage01NEWT.java index 925382901..8ccc73f34 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGImage01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGImage01NEWT.java @@ -146,7 +146,7 @@ public class TestJPEGImage01NEWT extends UITestCase { @Test public void testReadES2_RGBn() throws InterruptedException, IOException, MalformedURLException { final String fname = null == _fname ? "test-ntscN_3-01-160x90-90pct-yuv444-base.jpg" : _fname; - final URLConnection urlConn = IOUtil.getResource(this.getClass(), fname); + final URLConnection urlConn = IOUtil.getResource(fname, this.getClass().getClassLoader(), this.getClass()); testImpl(urlConn.getInputStream()); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTBenchmarkNewtAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTBenchmarkNewtAWT.java index 4fc774463..87a993de4 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTBenchmarkNewtAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTBenchmarkNewtAWT.java @@ -64,7 +64,7 @@ public class TestJPEGJoglAWTBenchmarkNewtAWT extends UITestCase { { final long t0 = System.currentTimeMillis(); for(int i = 0; i< loops; i++ ) { - final URLConnection urlConn = IOUtil.getResource(this.getClass(), fname); + final URLConnection urlConn = IOUtil.getResource(fname, this.getClass().getClassLoader(), this.getClass()); final InputStream istream = urlConn.getInputStream(); final JPEGImage image = JPEGImage.read(istream); // parsing & completion done !!! final int internalFormat = (image.getBytesPerPixel()==4)?GL.GL_RGBA:GL.GL_RGB; @@ -92,7 +92,7 @@ public class TestJPEGJoglAWTBenchmarkNewtAWT extends UITestCase { { final long t0 = System.currentTimeMillis(); for(int i = 0; i< loops; i++ ) { - final URLConnection urlConn = IOUtil.getResource(this.getClass(), fname); + final URLConnection urlConn = IOUtil.getResource(fname, this.getClass().getClassLoader(), this.getClass()); final InputStream istream = urlConn.getInputStream(); final JPEGImage image = JPEGImage.read(istream, TextureData.ColorSpace.YCbCr); // parsing & completion done !!! final int internalFormat = (image.getBytesPerPixel()==4)?GL.GL_RGBA:GL.GL_RGB; @@ -120,7 +120,7 @@ public class TestJPEGJoglAWTBenchmarkNewtAWT extends UITestCase { { final long t0 = System.currentTimeMillis(); for(int i = 0; i< loops; i++ ) { - final URLConnection urlConn = IOUtil.getResource(this.getClass(), fname); + final URLConnection urlConn = IOUtil.getResource(fname, this.getClass().getClassLoader(), this.getClass()); final InputStream istream = urlConn.getInputStream(); Buffer data = null; try { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTCompareNewtAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTCompareNewtAWT.java index d5c80553d..b48000046 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTCompareNewtAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGJoglAWTCompareNewtAWT.java @@ -101,7 +101,7 @@ public class TestJPEGJoglAWTCompareNewtAWT extends UITestCase { } GLWindow testJOGLJpeg(final String fname) throws InterruptedException, IOException { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), fname); + final URLConnection testTextureUrlConn = IOUtil.getResource(fname, this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); final InputStream istream = testTextureUrlConn.getInputStream(); Assert.assertNotNull(istream); @@ -160,7 +160,7 @@ public class TestJPEGJoglAWTCompareNewtAWT extends UITestCase { } GLWindow testAWTJpeg(final String fname, final int xpos) throws InterruptedException, IOException { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), fname); + final URLConnection testTextureUrlConn = IOUtil.getResource(fname, this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); final InputStream istream = testTextureUrlConn.getInputStream(); Assert.assertNotNull(istream); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java index 114561666..b43fba479 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestJPEGTextureFromFileNEWT.java @@ -82,63 +82,63 @@ public class TestJPEGTextureFromFileNEWT extends UITestCase { @Before public void initTest() throws IOException { { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_3-01-160x90-90pct-yuv444-base.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_3-01-160x90-90pct-yuv444-base.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream01YUV444_Base = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream01YUV444_Base); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_3-01-160x90-90pct-yuv444-prog.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_3-01-160x90-90pct-yuv444-prog.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream01YUV444_Prog = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream01YUV444_Prog); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_3-01-160x90-60pct-yuv422h-base.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_3-01-160x90-60pct-yuv422h-base.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream01YUV422h_Base = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream01YUV422h_Base); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_3-01-160x90-60pct-yuv422h-prog.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_3-01-160x90-60pct-yuv422h-prog.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream01YUV422h_Prog = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream01YUV422h_Prog); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "j1-baseline.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("j1-baseline.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream02YUV420_Base = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream02YUV420_Base); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "j2-progressive.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("j2-progressive.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream02YUV420_Prog = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream02YUV420_Prog); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "j3-baseline_gray.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("j3-baseline_gray.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream02YUV420_BaseGray = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream02YUV420_BaseGray); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-cmyk-01.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-cmyk-01.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream03CMYK_01 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream03CMYK_01); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ycck-01.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ycck-01.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream03YCCK_01 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream03YCCK_01); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "bug745_qttdef_post_frame.jpg"); + final URLConnection testTextureUrlConn = IOUtil.getResource("bug745_qttdef_post_frame.jpg", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream04QTTDefPostFrame = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream04QTTDefPostFrame); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect00NEWT.java index 3918b6cb7..0506f840e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect00NEWT.java @@ -128,7 +128,7 @@ public class TestPNGPixelRect00NEWT extends UITestCase { final File out2F_f=new File(getSimpleTestName(".")+"-02-"+basename+"-flipped.png"); final File out2R_f=new File(getSimpleTestName(".")+"-03-"+basename+"-reversed.png"); final File out2RF_f=new File(getSimpleTestName(".")+"-04-"+basename+"-reversed_flipped.png"); - final URLConnection urlConn = IOUtil.getResource(this.getClass(), pathname+basename+".png"); + final URLConnection urlConn = IOUtil.getResource(pathname+basename+".png", this.getClass().getClassLoader(), this.getClass()); if( null == urlConn ) { throw new IOException("Cannot find "+pathname+basename+".png"); } @@ -205,7 +205,7 @@ public class TestPNGPixelRect00NEWT extends UITestCase { System.err.println("Test02: "+pathname+basename+".png, destFmt "+destFmt+", destMinStrideInBytes "+destMinStrideInBytes+", destIsGLOriented "+destIsGLOriented); final File out1_f=new File(getSimpleTestName(".")+"-"+basename+"-orig.png"); - final URLConnection urlConn = IOUtil.getResource(this.getClass(), pathname+basename+".png"); + final URLConnection urlConn = IOUtil.getResource(pathname+basename+".png", this.getClass().getClassLoader(), this.getClass()); final PNGPixelRect image1 = PNGPixelRect.read(urlConn.getInputStream(), destFmt, false /* directBuffer */, destMinStrideInBytes, destIsGLOriented); System.err.println("PNGPixelRect - Orig: "+image1); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java index e299932b3..b6a047d03 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java @@ -156,7 +156,7 @@ public class TestPNGPixelRect01NEWT extends UITestCase { if( null == _fname ) { return; } - final URLConnection urlConn = IOUtil.getResource(this.getClass(), _fname); + final URLConnection urlConn = IOUtil.getResource(_fname, this.getClass().getClassLoader(), this.getClass()); if( null == urlConn ) { throw new IOException("Cannot find "+_fname+".png"); } @@ -170,7 +170,7 @@ public class TestPNGPixelRect01NEWT extends UITestCase { } for(int i=0; i<PNGTstFiles.allBasenames.length; i++) { final String basename = PNGTstFiles.allBasenames[i]; - final URLConnection urlConn = IOUtil.getResource(this.getClass(), basename+".png"); + final URLConnection urlConn = IOUtil.getResource(basename+".png", this.getClass().getClassLoader(), this.getClass()); if( null == urlConn ) { throw new IOException("Cannot find "+basename+".png"); } @@ -184,7 +184,7 @@ public class TestPNGPixelRect01NEWT extends UITestCase { } for(int i=0; i<PNGTstFiles.greyBasenames.length; i++) { final String basename = PNGTstFiles.greyBasenames[i]; - final URLConnection urlConn = IOUtil.getResource(this.getClass(), basename+".png"); + final URLConnection urlConn = IOUtil.getResource(basename+".png", this.getClass().getClassLoader(), this.getClass()); if( null == urlConn ) { throw new IOException("Cannot find "+basename+".png"); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileAWT.java index 2d6b6da71..157fffb90 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileAWT.java @@ -86,7 +86,7 @@ public class TestPNGTextureFromFileAWT extends UITestCase { grayTextureStream = TestPNGTextureFromFileAWT.class.getResourceAsStream( "grayscale_texture.png" ); Assert.assertNotNull(grayTextureStream); { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_3-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_3-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileNEWT.java index a82767f9a..d7017465e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGTextureFromFileNEWT.java @@ -82,44 +82,44 @@ public class TestPNGTextureFromFileNEWT extends UITestCase { grayTextureStream = TestPNGTextureFromFileNEWT.class.getResourceAsStream( "grayscale_texture.png" ); Assert.assertNotNull(grayTextureStream); { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_3-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_3-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamN_3 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamN_3); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscN_4-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscN_4-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamN_4 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamN_4); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscNG4-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscNG4-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamNG4 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamNG4); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscI_3-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscI_3-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamI_3 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamI_3); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscIG3-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscIG3-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamIG3 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamIG3); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscI_4-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscI_4-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamI_4 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamI_4); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscIG4-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscIG4-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamIG4 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamIG4); @@ -127,13 +127,13 @@ public class TestPNGTextureFromFileNEWT extends UITestCase { { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscP_3-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscP_3-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamP_3 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamP_3); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-ntscP_4-01-160x90.png"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-ntscP_4-01-160x90.png", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStreamP_4 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStreamP_4); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java index 618797e66..653ccadfd 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java @@ -83,7 +83,7 @@ public class TestPixelFormatUtil01NEWT extends UITestCase { { System.err.println("Test01: "+pathname+basename+".png, srcFmt "+srcFmt+", destMinStrideInBytes "+destMinStrideInBytes+", destIsGLOriented "+destIsGLOriented); - final URLConnection urlConn = IOUtil.getResource(this.getClass(), pathname+basename+".png"); + final URLConnection urlConn = IOUtil.getResource(pathname+basename+".png", this.getClass().getClassLoader(), this.getClass()); final PNGPixelRect image1 = PNGPixelRect.read(urlConn.getInputStream(), srcFmt, false /* directBuffer */, destMinStrideInBytes, false /* isGLOriented */); System.err.println("PNGPixelRect - Orig: "+image1); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTGATextureFromFileNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTGATextureFromFileNEWT.java index 6e0af17da..23f4593d8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTGATextureFromFileNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTGATextureFromFileNEWT.java @@ -69,19 +69,19 @@ public class TestTGATextureFromFileNEWT extends UITestCase { @Before public void initTest() throws IOException { { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "test-u32.tga"); + final URLConnection testTextureUrlConn = IOUtil.getResource("test-u32.tga", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream01U32 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream01U32); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "bug744-rle32.tga"); + final URLConnection testTextureUrlConn = IOUtil.getResource("bug744-rle32.tga", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream02RLE32 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream02RLE32); } { - final URLConnection testTextureUrlConn = IOUtil.getResource(this.getClass(), "bug982.rle32.256x256.tga"); + final URLConnection testTextureUrlConn = IOUtil.getResource("bug982.rle32.256x256.tga", this.getClass().getClassLoader(), this.getClass()); Assert.assertNotNull(testTextureUrlConn); testTextureStream03RLE32 = testTextureUrlConn.getInputStream(); Assert.assertNotNull(testTextureStream03RLE32); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTextureIONEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTextureIONEWT.java new file mode 100644 index 000000000..56d9d481e --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestTextureIONEWT.java @@ -0,0 +1,165 @@ +/** + * Copyright 2015 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.util.texture; + +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.test.junit.jogl.demos.TextureDraw01Accessor; +import com.jogamp.opengl.test.junit.jogl.demos.es2.TextureDraw01ES2Listener; +import com.jogamp.opengl.test.junit.jogl.demos.gl2.TextureDraw01GL2Listener; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.texture.ImageType; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +import org.junit.Assert; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestTextureIONEWT extends UITestCase { + static long duration = 100; // ms + + ImageTstFiles imageTstFiles; + + @Before + public void initTest() throws IOException { + imageTstFiles = new ImageTstFiles(); + imageTstFiles.init(); + } + + @After + public void cleanupTest() { + imageTstFiles.clear(); + } + + public void testImpl(final List<ImageTstFiles.NamedInputStream> streams, final ImageType expImageType) throws InterruptedException, IOException { + for(int i=0; i<streams.size(); i++) { + final ImageTstFiles.NamedInputStream s = streams.get(i); + System.err.printf("Test %3d: path %s, exp-type %s%n", i, s.basePath, expImageType); + testImpl(s.stream, expImageType); + } + } + public void testImpl(final InputStream istream, final ImageType expImageType) throws InterruptedException, IOException { + final GLReadBufferUtil screenshot = new GLReadBufferUtil(true, false); + final GLProfile glp = GLProfile.isAvailable(GLProfile.GL2ES2) ? GLProfile.getGL2ES2() : GLProfile.getDefault(); + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(1); + + final TextureData texData = TextureIO.newTextureData(glp, istream, false /* mipmap */, expImageType.type); + System.err.println("TextureData: "+texData); + Assert.assertEquals(expImageType, texData.getSourceImageType()); + + final GLWindow glad = GLWindow.create(caps); + glad.setTitle("TestTextureIONEWT."+expImageType.type); + // Size OpenGL to Video Surface + glad.setSize(texData.getWidth(), texData.getHeight()); + + // load texture from file inside current GL context to match the way + // the bug submitter was doing it + final GLEventListener gle = glp.isGL2ES2() ? new TextureDraw01ES2Listener( texData, 0 ) : new TextureDraw01GL2Listener( texData ) ; + glad.addGLEventListener(gle); + glad.addGLEventListener(new GLEventListener() { + boolean shot = false; + + @Override public void init(final GLAutoDrawable drawable) {} + + public void display(final GLAutoDrawable drawable) { + // 1 snapshot + if(null!=((TextureDraw01Accessor)gle).getTexture() && !shot) { + shot = true; + snapshot(0, null, drawable.getGL(), screenshot, TextureIO.PNG, null); + } + } + + @Override public void dispose(final GLAutoDrawable drawable) { } + @Override public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { } + }); + + final Animator animator = new Animator(glad); + animator.setUpdateFPSFrames(60, null); + final QuitAdapter quitAdapter = new QuitAdapter(); + glad.addKeyListener(quitAdapter); + glad.addWindowListener(quitAdapter); + glad.setVisible(true); + animator.start(); + + while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + Thread.sleep(100); + } + + animator.stop(); + glad.destroy(); + } + + @Test + public void test01AllPNG() throws InterruptedException, IOException { + testImpl(imageTstFiles.pngStreams, new ImageType(ImageType.T_PNG)); + } + + @Test + public void test02AllJPG() throws InterruptedException, IOException { + testImpl(imageTstFiles.jpgStreams, new ImageType(ImageType.T_JPG)); + } + + @Test + public void test03AllTGA() throws InterruptedException, IOException { + testImpl(imageTstFiles.tgaStreams, new ImageType(ImageType.T_TGA)); + } + + @Test + public void test04AllDDS() throws InterruptedException, IOException { + testImpl(imageTstFiles.ddsStreams, new ImageType(ImageType.T_DDS)); + } + + public static void main(final String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + duration = MiscUtils.atol(args[i], duration); + } + } + org.junit.runner.JUnitCore.main(TestTextureIONEWT.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestBug1211IRQ00NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestBug1211IRQ00NEWT.java new file mode 100644 index 000000000..186c3a79a --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestBug1211IRQ00NEWT.java @@ -0,0 +1,324 @@ +/** + * Copyright 2015 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; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.common.util.SourcedInterruptedException; +import com.jogamp.common.util.VersionUtil; +import com.jogamp.junit.util.SingletonJunitCase; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.util.Animator; + +/** + * Unit test to identify Thread.interrupt() caller for DefaultEDTUtil.invokeImpl(..) wait interruption. + * <ul> + * <li>resize</li> + * <li>create/destroy</li> + * </ul> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestBug1211IRQ00NEWT extends SingletonJunitCase { + static long durationTest00 = 1000; // ms + static long durationTest01 = 1000; // ms + static int width = 800; + static int height = 600; + + static GLWindow createWindow(final GLCapabilitiesImmutable caps) { + Assert.assertNotNull(caps); + // + // Create native windowing resources .. X11/Win/OSX + // + final GLWindow glWindow = GLWindow.create(caps); + Assert.assertNotNull(glWindow); + glWindow.setSize(width, height); + + glWindow.setUpdateFPSFrames(1, null); + + final GearsES2 demo = new GearsES2(); + demo.setVerbose(false); + glWindow.addGLEventListener(demo); + + return glWindow; + } + + static void destroyWindow(final GLWindow glWindow) throws InterruptedException { + if(null!=glWindow) { + glWindow.destroy(); + Assert.assertEquals(false,glWindow.isNativeValid()); + } + } + + static class MyThread extends InterruptSource.Thread implements Thread.UncaughtExceptionHandler { + volatile boolean myThreadStarted = false; + volatile boolean myThreadStopped = false; + + public MyThread(final Runnable target, final String name) { + super(null, target, name); + setUncaughtExceptionHandler(this); + } + + public static void testInterrupted1() throws InterruptedException { + if( java.lang.Thread.interrupted() ) { + throw SourcedInterruptedException.wrap( + new InterruptedException(java.lang.Thread.currentThread().getName()+".testInterrupted -> TRUE (silent interruption)")); + } + } + public synchronized void testInterrupted(final boolean ignore) throws InterruptedException { + if( isInterrupted() ) { + final boolean current; + if( this == java.lang.Thread.currentThread() ) { + java.lang.Thread.interrupted(); // clear! + current = true; + } else { + current = false; + } + final int counter = getInterruptCounter(false); + final Throwable source = getInterruptSource(true); + final InterruptedException e = new SourcedInterruptedException( + getName()+".testInterrupted -> TRUE (current "+current+", counter "+counter+")", + null, source); + if( !ignore ) { + throw e; + } else { + ExceptionUtils.dumpThrowable("Ignored", e); + } + } + } + + @Override + public void run() { + myThreadStarted = true; + try { + super.run(); + } finally { + myThreadStopped = true; + } + } + + @Override + public void uncaughtException(final java.lang.Thread t, final Throwable e) { + System.err.println("UncaughtException on Thread "+t.getName()+": "+e.getMessage()); + ExceptionUtils.dumpThrowable("UncaughtException", e); + } + } + + + volatile boolean interrupt1 = false; + volatile boolean interrupt2 = false; + volatile boolean interruptInit0 = false; + + public void initTest() { + interrupt1 = false; + interrupt2 = false; + } + + /** + * Test whether resize triggers DefaultEDTUtil.invokeImpl(..) wait interruption. + */ + public void subTest00() { + final MyThread t = (MyThread)Thread.currentThread(); + final GLCapabilities caps = new GLCapabilities(GLProfile.getDefault()); + Assert.assertNotNull(caps); + final GLWindow window1 = createWindow(caps); // local + final EDTUtil edt = window1.getScreen().getDisplay().getEDTUtil(); + final Animator anim = new Animator(window1); + try { + window1.setVisible(true); + Assert.assertEquals(true,window1.isVisible()); + Assert.assertEquals(true,window1.isNativeValid()); + anim.start(); + boolean ok = true; + for(int i=0; ok && i*100<durationTest00; i++) { + Thread.sleep(100); + final int ow = window1.getWidth(); + final int oh = window1.getHeight(); + final int nw, nh; + if( 0 == i % 2 ) { + nw = ow + 100; + nh = oh + 100; + } else { + nw = ow - 100; + nh = oh - 100; + } + System.err.println("test00.resize["+i+"]: "+ow+"x"+oh+" -> "+nw+"x"+nh); + window1.setSize(nw, nh); + ok = 0==t.getInterruptCounter(false) && !t.isInterrupted() && edt.isRunning() && anim.isAnimating(); + t.testInterrupted(false); + } + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("InterruptedException-1", e); + interrupt1 = true; + } + try { + anim.stop(); + destroyWindow(window1); + t.testInterrupted(false); + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("InterruptedException-2", e); + interrupt2 = true; + } + Assert.assertEquals("interruptCounter not zero", 0, t.getInterruptCounter(false)); + Assert.assertFalse("interrupt() occured!", t.isInterrupted()); + Assert.assertFalse("Interrupt-1 occured!", interrupt1); + Assert.assertFalse("Interrupt-2 occured!", interrupt2); + } + + /** + * Test whether create/destroy triggers DefaultEDTUtil.invokeImpl(..) wait interruption. + */ + public void subTest01() { + final MyThread t = (MyThread)Thread.currentThread(); + GLWindow lastWindow = null; + try { + final boolean ok = true; + for(int i=0; ok && i*100<durationTest01; i++) { + final GLCapabilities caps = new GLCapabilities(GLProfile.getDefault()); + Assert.assertNotNull(caps); + final GLWindow window1 = createWindow(caps); // local + lastWindow = window1; + window1.setVisible(true); + Assert.assertEquals(true,window1.isVisible()); + Assert.assertEquals(true,window1.isNativeValid()); + System.err.println("test01.create["+i+"]: "+window1.getStateMaskString()+", "+window1.getWidth()+"x"+window1.getHeight()); + final Animator anim = new Animator(window1); + anim.start(); + Thread.sleep(100); + anim.stop(); + destroyWindow(window1); + t.testInterrupted(false); + } + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("InterruptedException-1", e); + interrupt1 = true; + } + try { + destroyWindow(lastWindow); + t.testInterrupted(false); + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("InterruptedException-2", e); + interrupt2 = true; + } + Assert.assertEquals("interruptCounter not zero", 0, t.getInterruptCounter(false)); + Assert.assertFalse("interrupt() occured!", t.isInterrupted()); + Assert.assertFalse("Interrupt-1 occured!", interrupt1); + Assert.assertFalse("Interrupt-2 occured!", interrupt2); + } + + @Test + public void testAll() { + interruptInit0 = false; + final MyThread t = new MyThread(new Runnable() { + public void run() { + final MyThread t = (MyThread)Thread.currentThread(); + TestBug1211IRQ00NEWT test = null; + try { + System.err.println(VersionUtil.getPlatformInfo()); + GLProfile.initSingleton(); + test = new TestBug1211IRQ00NEWT(); + t.testInterrupted(false); + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("InterruptedException-Init0", e); + interruptInit0 = true; + test = null; + } + t.clearInterruptSource(); + if( null != test ) { + test.initTest(); + test.subTest00(); + + test.initTest(); + test.subTest01(); + } + } + }, "MyMainThread"); + t.start(); + boolean interrupted = false; + try { + MyThread.testInterrupted1(); + while( !t.myThreadStarted ) { + Thread.yield(); + MyThread.testInterrupted1(); + } + while( !t.myThreadStopped ) { + Thread.yield(); + MyThread.testInterrupted1(); + } + MyThread.testInterrupted1(); + } catch (final InterruptedException e) { + ExceptionUtils.dumpThrowable("InterruptedException-All", e); + interrupted = true; + } + Assert.assertFalse("Thread Interrupt-All occured!", interrupted); + Assert.assertFalse("Interrupt-Init0 occured!", interruptInit0); + } + + static int atoi(final String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (final Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(final String args[]) throws IOException { + // We like to allow concurrent manual tests! + SingletonJunitCase.enableSingletonLock(false); + + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time00")) { + durationTest00 = atoi(args[++i]); + } else if(args[i].equals("-time01")) { + durationTest01 = atoi(args[++i]); + } else if(args[i].equals("-width")) { + width = atoi(args[++i]); + } else if(args[i].equals("-height")) { + height = atoi(args[++i]); + } + } + System.out.println("durationTest00: "+durationTest00); + System.out.println("durationTest01: "+durationTest01); + System.out.println("defaultSize : "+width+"x"+height); + final String tstname = TestBug1211IRQ00NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} 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 9dd96acdd..38620ad92 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java @@ -49,6 +49,8 @@ import com.jogamp.nativewindow.AbstractGraphicsDevice; public class TestGLWindows00NEWT extends UITestCase { static GLProfile glp; static int width, height; + static boolean manual = false; + static int loopVisibleToggle = 10; static long durationPerTest = 100; // ms @BeforeClass @@ -58,7 +60,7 @@ public class TestGLWindows00NEWT extends UITestCase { glp = GLProfile.getDefault(); } - static GLWindow createWindow(final Screen screen, final GLCapabilitiesImmutable caps) + static GLWindow createWindow(final Screen screen, final GLCapabilitiesImmutable caps, final boolean undecor) throws InterruptedException { Assert.assertNotNull(caps); @@ -78,7 +80,9 @@ public class TestGLWindows00NEWT extends UITestCase { final GLEventListener demo = new GearsES2(); glWindow.addGLEventListener(demo); + glWindow.setUndecorated(undecor); glWindow.setSize(512, 512); + System.err.println("XXX VISIBLE.0 -> TRUE"); glWindow.setVisible(true); Assert.assertEquals(true,glWindow.isVisible()); Assert.assertEquals(true,glWindow.isNativeValid()); @@ -90,25 +94,103 @@ public class TestGLWindows00NEWT extends UITestCase { if(null!=glWindow) { glWindow.destroy(); Assert.assertEquals(false,glWindow.isNativeValid()); + Assert.assertEquals(false,glWindow.isVisible()); } } @Test - public void testWindow00() throws InterruptedException { + public void test01WindowCreateSimple() throws InterruptedException { + if( manual ) { + return; + } final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); - final GLWindow window1 = createWindow(null, caps); // local - Assert.assertEquals(true,window1.isNativeValid()); - Assert.assertEquals(true,window1.isVisible()); - final AbstractGraphicsDevice device1 = window1.getScreen().getDisplay().getGraphicsDevice(); + final GLWindow window = createWindow(null, caps, false /* undecor */); // local + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + final AbstractGraphicsDevice device1 = window.getScreen().getDisplay().getGraphicsDevice(); System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1)); for(int state=0; state*100<durationPerTest; state++) { Thread.sleep(100); } - destroyWindow(window1); + destroyWindow(window); + } + + @Test + public void test02WindowCreateUndecor() throws InterruptedException { + if( manual ) { + return; + } + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, true /* undecor */); // local + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + final AbstractGraphicsDevice device1 = window.getScreen().getDisplay().getGraphicsDevice(); + System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1)); + + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + destroyWindow(window); + } + + @Test + public void test11WindowSimpleToggleVisibility() throws InterruptedException { + test1xWindowToggleVisibility(false /* undecor */, loopVisibleToggle); + } + @Test + public void test12WindowUndecorToggleVisibility() throws InterruptedException { + if( manual ) { + return; + } + test1xWindowToggleVisibility(true /* undecor */, loopVisibleToggle); + } + private void test1xWindowToggleVisibility(final boolean undecor, final int loopVisibleToggle) throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, undecor); // local + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + window.display(); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + for(int i=1; i<=loopVisibleToggle; i++) { + System.err.println("XXX VISIBLE."+i+" -> FALSE"); + window.setVisible(false); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + window.display(); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + + System.err.println("XXX VISIBLE."+i+" -> TRUE"); + window.setVisible(true); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + window.display(); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + } + + destroyWindow(window); } static int atoi(final String a) { @@ -123,6 +205,10 @@ public class TestGLWindows00NEWT extends UITestCase { for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { durationPerTest = atoi(args[++i]); + } else if(args[i].equals("-loopvt")) { + loopVisibleToggle = atoi(args[++i]); + } else if(args[i].equals("-manual")) { + manual = true; } } System.out.println("durationPerTest: "+durationPerTest); 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 ab8304504..00b31f400 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java @@ -59,8 +59,7 @@ public class TestGLWindows01NEWT extends UITestCase { } static GLWindow createWindow(final Screen screen, final GLCapabilities caps, - final int width, final int height, final boolean onscreen, final boolean undecorated, - final boolean addGLEventListenerAfterVisible) + final int width, final int height, final boolean onscreen, final boolean addGLEventListenerAfterVisible) throws InterruptedException { Assert.assertNotNull(caps); @@ -79,7 +78,6 @@ public class TestGLWindows01NEWT extends UITestCase { Assert.assertNotNull(glWindow); } - glWindow.setUndecorated(onscreen && undecorated); Assert.assertEquals(false,glWindow.isVisible()); Assert.assertEquals(false,glWindow.isNativeValid()); @@ -122,16 +120,47 @@ public class TestGLWindows01NEWT extends UITestCase { if(null!=glWindow) { glWindow.destroy(); Assert.assertEquals(false,glWindow.isNativeValid()); + Assert.assertEquals(false,glWindow.isVisible()); } } + + @Test + public void test01WindowSimple() throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, width, height, + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); + System.out.println("Created: "+window); + int state; + for(state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + System.out.println("duration: "+window.getTotalFPSDuration()); + destroyWindow(window); + } + + @Test + public void test02WindowSimple() throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, width, height, + true /* onscreen */, true /*addGLEventListenerAfterVisible*/); + System.out.println("Created: "+window); + int state; + for(state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + System.out.println("duration: "+window.getTotalFPSDuration()); + destroyWindow(window); + } + @Test - public void testWindowNativeRecreate01aSimple() throws InterruptedException { + public void test10WindowNativeRecreateSimple() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertEquals(true,window.isNativeValid()); Assert.assertEquals(true,window.isVisible()); @@ -155,12 +184,11 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowNativeRecreate01bSimple() throws InterruptedException { + public void test11WindowNativeRecreateSimple() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - true /*addGLEventListenerAfterVisible*/); + true /* onscreen */, true /*addGLEventListenerAfterVisible*/); Assert.assertEquals(true,window.isNativeValid()); Assert.assertEquals(true,window.isVisible()); @@ -184,44 +212,11 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowDecor01aSimple() throws InterruptedException { - final GLCapabilities caps = new GLCapabilities(glp); - Assert.assertNotNull(caps); - final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); - System.out.println("Created: "+window); - int state; - for(state=0; state*100<durationPerTest; state++) { - Thread.sleep(100); - } - System.out.println("duration: "+window.getTotalFPSDuration()); - destroyWindow(window); - } - - @Test - public void testWindowDecor01bSimple() throws InterruptedException { - final GLCapabilities caps = new GLCapabilities(glp); - Assert.assertNotNull(caps); - final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - true /*addGLEventListenerAfterVisible*/); - System.out.println("Created: "+window); - int state; - for(state=0; state*100<durationPerTest; state++) { - Thread.sleep(100); - } - System.out.println("duration: "+window.getTotalFPSDuration()); - destroyWindow(window); - } - - @Test - public void testWindowDecor02DestroyWinTwiceA() throws InterruptedException { + public void test21WindowDestroyWinTwiceA() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); int state; for(state=0; state*100<durationPerTest; state++) { Thread.sleep(100); @@ -231,7 +226,7 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowDecor03TwoWinOneDisplay() throws InterruptedException { + public void test22WindowTwoWinOneDisplay() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); @@ -241,13 +236,11 @@ public class TestGLWindows01NEWT extends UITestCase { final Screen screen = NewtFactory.createScreen(display, 0); // screen 0 Assert.assertNotNull(screen); final GLWindow window1 = createWindow(screen, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window1); final GLWindow window2 = createWindow(screen, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window2); Assert.assertEquals(1,Display.getActiveDisplayNumber()); @@ -281,7 +274,7 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowDecor03TwoWinTwoDisplays() throws InterruptedException { + public void test23WindowTwoWinTwoDisplays() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); @@ -294,15 +287,13 @@ public class TestGLWindows01NEWT extends UITestCase { final Screen screen1 = NewtFactory.createScreen(display1, 0); // screen 0 Assert.assertNotNull(screen1); final GLWindow window1 = createWindow(screen1, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window1); final Screen screen2 = NewtFactory.createScreen(display2, 0); // screen 0 Assert.assertNotNull(screen2); final GLWindow window2 = createWindow(screen2, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window2); Assert.assertEquals(2,Display.getActiveDisplayNumber()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestWindowAndPointerIconNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestWindowAndPointerIconNEWT.java index 0ef554ec2..d613f7d94 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestWindowAndPointerIconNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestWindowAndPointerIconNEWT.java @@ -94,7 +94,7 @@ public class TestWindowAndPointerIconNEWT extends SingletonJunitCase { final int idx = 0; { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "arrow-red-alpha-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-red-alpha-64x64.png" }, glWindow.getClass().getClassLoader(), null); try { _pointerIcon = disp.createPointerIcon(res, 0, 0); System.err.printf("Create PointerIcon #%02d: %s%n", idx, _pointerIcon.toString()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestWindows02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestWindows02NEWT.java new file mode 100644 index 000000000..5cdb7e118 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestWindows02NEWT.java @@ -0,0 +1,158 @@ +/** + * 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; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import com.jogamp.nativewindow.*; + +import com.jogamp.newt.*; +import java.io.IOException; + +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestWindows02NEWT extends UITestCase { + static int width, height; + static long durationPerTest = 100; // ms + + @BeforeClass + public static void initClass() { + NativeWindowFactory.initSingleton(); + width = 800; + height = 600; + } + + static Window createWindow(final Capabilities caps, final int x, final int y, final int width, final int height, final boolean onscreen, final boolean undecorated) throws InterruptedException { + final boolean userPos = x>=0 && y>=0 ; // user has specified a position + + Assert.assertNotNull(caps); + caps.setOnscreen(onscreen); + // System.out.println("Requested: "+caps); + + // + // Create native windowing resources .. X11/Win/OSX + // + final Window window = NewtFactory.createWindow(caps); + Assert.assertNotNull(window); + final Screen screen = window.getScreen(); + final Display display = screen.getDisplay(); + window.setUndecorated(onscreen && undecorated); + if(userPos) { + window.setPosition(x, y); + } + window.setSize(width, height); + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + window.setVisible(true); + // System.err.println("************* Created: "+window); + + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(width, window.getWidth()); + Assert.assertEquals(height, window.getHeight()); + + final CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getChosenCapabilities(); + Assert.assertNotNull(chosenCapabilities); + Assert.assertTrue(chosenCapabilities.getGreenBits()>=5); + Assert.assertTrue(chosenCapabilities.getBlueBits()>=5); + Assert.assertTrue(chosenCapabilities.getRedBits()>=5); + Assert.assertEquals(chosenCapabilities.isOnscreen(),onscreen); + + return window; + } + + static void destroyWindow(final Window window, final boolean last) { + if(null==window) { + return; + } + final Screen screen = window.getScreen(); + final Display display = screen.getDisplay(); + window.destroy(); + // System.err.println("************* Destroyed: "+window); + if(last) { + Assert.assertEquals(false,screen.isNativeValid()); + Assert.assertEquals(false,display.isNativeValid()); + } else { + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(true,display.isNativeValid()); + } + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + } + + + @Test + public void test01WindowDefault() throws InterruptedException { + final Capabilities caps = new Capabilities(); + Assert.assertNotNull(caps); + + final Window window = createWindow(caps, -1, -1, width, height, true /* onscreen */, false /* undecorated */); + final CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getChosenCapabilities(); + System.err.println("XXX: "+chosenCapabilities); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + destroyWindow(window, true); + } + + @Test + public void test02WindowDefault() throws InterruptedException { + final Capabilities caps = new Capabilities(); + Assert.assertNotNull(caps); + caps.setBackgroundOpaque(false); + + final Window window = createWindow(caps, -1, -1, width, height, true /* onscreen */, false /* undecorated */); + final CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getChosenCapabilities(); + System.err.println("XXX: "+chosenCapabilities); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + destroyWindow(window, true); + } + + public static void main(final String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = MiscUtils.atol(args[++i], durationPerTest); + } + } + System.out.println("durationPerTest: "+durationPerTest); + final String tstname = TestWindows02NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java b/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java index 39c6c9f4d..5f88d1c6f 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/event/BaseNewtEventModifiers.java @@ -40,6 +40,7 @@ import org.junit.FixMethodOrder; import org.junit.Test ; import org.junit.runners.MethodSorters; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.RunnableTask; import com.jogamp.newt.event.MouseEvent; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; @@ -344,20 +345,17 @@ public abstract class BaseNewtEventModifiers extends UITestCase { } _testMouseListener.setModifierCheckEnabled( true ) ; - Throwable throwable = null; // final Object sync = new Object(); final RunnableTask rt = new RunnableTask( testAction, null, true, System.err ); try { // synchronized(sync) { - new Thread(rt, "Test-Thread").start(); + new InterruptSource.Thread(null, rt, "Test-Thread").start(); int i=0; - while( !rt.isExecuted() && null == throwable ) { + while( rt.isInQueue() ) { System.err.println("WAIT-till-done: eventDispatch() #"+i++); eventDispatch(); } - if(null==throwable) { - throwable = rt.getThrowable(); - } + final Throwable throwable = rt.getThrowable(); if(null!=throwable) { throw new RuntimeException(throwable); } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/event/TestParentingFocus03KeyTraversalAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/event/TestParentingFocus03KeyTraversalAWT.java index cade05478..283fc262a 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/event/TestParentingFocus03KeyTraversalAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/event/TestParentingFocus03KeyTraversalAWT.java @@ -53,6 +53,7 @@ import com.jogamp.opengl.*; import com.jogamp.opengl.util.Animator; import com.jogamp.newt.*; import com.jogamp.newt.opengl.*; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; @@ -64,12 +65,19 @@ import jogamp.newt.driver.DriverClearFocus; import com.jogamp.opengl.test.junit.util.*; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.newt.parenting.NewtAWTReparentingKeyAdapter; +import com.jogamp.opengl.test.junit.newt.parenting.NewtReparentingKeyAdapter; /** * Testing focus <i>key</i> traversal of an AWT component tree with {@link NewtCanvasAWT} attached. * <p> * {@link Frame} [ Button*, {@link NewtCanvasAWT} . {@link GLWindow} ] * </p> + * <p> + * The demo code uses {@link NewtReparentingKeyAdapter} including {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000}, and many more, see {@link #main(String[])} + * </p> */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestParentingFocus03KeyTraversalAWT extends UITestCase { @@ -154,7 +162,7 @@ public class TestParentingFocus03KeyTraversalAWT extends UITestCase { final GLEventListener demo1 = new GearsES2(1); setDemoFields(demo1, glWindow1, false); glWindow1.addGLEventListener(demo1); - glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1, null)); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); glWindow1.addKeyListener(new KeyAdapter() { public void keyReleased(final KeyEvent e) { if( !e.isPrintableKey() || e.isAutoRepeat() ) { 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 ae873eaf0..7e92c8438 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 @@ -1,5 +1,5 @@ /** - * Copyright 2011 JogAmp Community. All rights reserved. + * Copyright 2011, 2019 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: @@ -30,94 +30,37 @@ package com.jogamp.opengl.test.junit.newt.parenting; import java.awt.Frame; import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowHolder; import com.jogamp.nativewindow.util.InsetsImmutable; import com.jogamp.newt.Window; -import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; -import com.jogamp.opengl.test.junit.util.NEWTDemoListener; -import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.newt.opengl.util.NEWTDemoListener; -public class NewtAWTReparentingKeyAdapter extends NEWTDemoListener { +/** + * AWT specializing demo functionality of {@link NewtReparentingKeyAdapter}, includes {@link NEWTDemoListener}. + */ +public class NewtAWTReparentingKeyAdapter extends NewtReparentingKeyAdapter { final Frame frame; - final NewtCanvasAWT newtCanvasAWT; - public NewtAWTReparentingKeyAdapter(final Frame frame, final NewtCanvasAWT newtCanvasAWT, final GLWindow glWindow, final QuitAdapter quitAdapter) { - super(glWindow, quitAdapter, null); + public NewtAWTReparentingKeyAdapter(final Frame frame, final NativeWindowHolder winHolder, final GLWindow glWindow) { + super(winHolder, glWindow); this.frame = frame; - this.newtCanvasAWT = newtCanvasAWT; - } - - public void keyPressed(final KeyEvent e) { - if( e.isAutoRepeat() || e.isConsumed() ) { - return; - } - if( 0 == e.getModifiers() ) { // all modifiers go to super class .. - final int keySymbol = e.getKeySymbol(); - switch (keySymbol) { - case KeyEvent.VK_L: - e.setConsumed(true); - final com.jogamp.nativewindow.util.Point p0 = newtCanvasAWT.getNativeWindow().getLocationOnScreen(null); - final com.jogamp.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); - printlnState("[location]", "AWT "+p0+", NEWT "+p1); - break; - case KeyEvent.VK_R: - e.setConsumed(true); - quitAdapterOff(); - new Thread() { - public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); - if(glWindow.getParent()==null) { - printlnState("[reparent pre - glWin to HOME]"); - glWindow.reparentWindow(newtCanvasAWT.getNativeWindow(), -1, -1, 0 /* hints */); - } else { - if( null != frame ) { - final InsetsImmutable nInsets = glWindow.getInsets(); - final java.awt.Insets aInsets = frame.getInsets(); - int dx, dy; - if( nInsets.getTotalHeight()==0 ) { - dx = aInsets.left; - dy = aInsets.top; - } else { - dx = nInsets.getLeftWidth(); - dy = nInsets.getTopHeight(); - } - final int topLevelX = frame.getX()+frame.getWidth()+dx; - final int topLevelY = frame.getY()+dy; - printlnState("[reparent pre - glWin to TOP.1]", topLevelX+"/"+topLevelY+" - insets " + nInsets + ", " + aInsets); - glWindow.reparentWindow(null, topLevelX, topLevelY, 0 /* hint */); - } else { - printlnState("[reparent pre - glWin to TOP.0]"); - glWindow.reparentWindow(null, -1, -1, 0 /* hints */); - } - } - printlnState("[reparent post]"); - glWindow.requestFocus(); - glWindow.setExclusiveContextThread(t); - quitAdapterOn(); - } }.start(); - break; - } - } - super.keyPressed(e); } @Override public void setTitle() { - setTitle(frame, newtCanvasAWT, glWindow); + setTitle(frame, winHolder.getNativeWindow(), glWindow); } - public static void setTitle(final Frame frame, final NewtCanvasAWT glc, final Window win) { + public void setTitle(final Frame frame, final NativeWindow nw, final Window win) { final CapabilitiesImmutable chosenCaps = win.getChosenCapabilities(); final CapabilitiesImmutable reqCaps = win.getRequestedCapabilities(); final CapabilitiesImmutable caps = null != chosenCaps ? chosenCaps : reqCaps; final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl"; { - final java.awt.Rectangle b = glc.getBounds(); - frame.setTitle("NewtCanvasAWT["+capsA+"], win: ["+b.x+"/"+b.y+" "+b.width+"x"+b.height+"], pix: "+glc.getNativeWindow().getSurfaceWidth()+"x"+glc.getNativeWindow().getSurfaceHeight()); + frame.setTitle("Frame["+capsA+"], win: "+getNativeWinTitle(nw)); } - final float[] sDPI = win.getPixelsPerMM(new float[2]); - sDPI[0] *= 25.4f; - sDPI[1] *= 25.4f; - win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]); + super.setTitle(nw, win); } } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtJFXReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtJFXReparentingKeyAdapter.java new file mode 100644 index 000000000..3ed847ae3 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtJFXReparentingKeyAdapter.java @@ -0,0 +1,102 @@ +/** + * Copyright 2019 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 com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowHolder; +import com.jogamp.nativewindow.util.Insets; +import com.jogamp.nativewindow.util.InsetsImmutable; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; + +import javafx.geometry.Bounds; + +/** + * JavaFX specializing demo functionality of {@link NewtReparentingKeyAdapter}, includes {@link NEWTDemoListener}. + */ +public class NewtJFXReparentingKeyAdapter extends NewtReparentingKeyAdapter { + final javafx.stage.Stage frame; + + public NewtJFXReparentingKeyAdapter(final javafx.stage.Stage frame, final NativeWindowHolder winHolder, final GLWindow glWindow) { + super(winHolder, glWindow); + this.frame = frame; + } + + @Override + public void keyPressed(final KeyEvent e) { + if( e.isAutoRepeat() || e.isConsumed() ) { + return; + } + if( 0 == e.getModifiers() ) { // all modifiers go to super class .. + final int keySymbol = e.getKeySymbol(); + switch (keySymbol) { + case KeyEvent.VK_R: + e.setConsumed(true); + quitAdapterOff(); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + final java.lang.Thread t = glWindow.setExclusiveContextThread(null); + if(glWindow.getParent()==null) { + printlnState("[reparent pre - glWin to HOME: child pos "+winHolder.getNativeWindow().getX()+"/"+winHolder.getNativeWindow().getY()+"]"); + glWindow.reparentWindow(winHolder.getNativeWindow(), winHolder.getNativeWindow().getX(), winHolder.getNativeWindow().getY(), 0 /* hints */); + glWindow.setPosition(winHolder.getNativeWindow().getX(), winHolder.getNativeWindow().getY()); + } else { + final com.jogamp.nativewindow.util.Point p0 = winHolder.getNativeWindow().getLocationOnScreen(null); + final com.jogamp.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); + printlnState("[reparent pre - glWin to TOP.1] frame ", p0+", glWindow "+p1); + glWindow.reparentWindow(null, p1.getX(), p1.getY(), 0 /* hint */); + } + printlnState("[reparent post]"); + glWindow.requestFocus(); + glWindow.setExclusiveContextThread(t); + quitAdapterOn(); + } } ); + break; + } + } + super.keyPressed(e); + } + + @Override + public void setTitle() { + setTitle(frame, winHolder.getNativeWindow(), glWindow); + } + public void setTitle(final javafx.stage.Stage frame, final NativeWindow nw, final Window win) { + final CapabilitiesImmutable chosenCaps = win.getChosenCapabilities(); + final CapabilitiesImmutable reqCaps = win.getRequestedCapabilities(); + final CapabilitiesImmutable caps = null != chosenCaps ? chosenCaps : reqCaps; + final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl"; + { + frame.setTitle("Frame["+capsA+"], win: "+getNativeWinTitle(nw)); + } + super.setTitle(nw, win); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtReparentingKeyAdapter.java new file mode 100644 index 000000000..339230d48 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtReparentingKeyAdapter.java @@ -0,0 +1,111 @@ +/** + * Copyright 2011, 2019 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 com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowHolder; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; +import com.jogamp.opengl.GLAnimatorControl; + +/** + * Extending demo functionality of {@link NEWTDemoListener} + * <ul> + * <li>L: Print parent and (child) {@link GLWindow} location</li> + * <li>R: Toggel parenting (top-level/child)</li> + * </ul> + */ +public class NewtReparentingKeyAdapter extends NEWTDemoListener { + final NativeWindowHolder winHolder; + + public NewtReparentingKeyAdapter(final NativeWindowHolder winHolder, final GLWindow glWindow) { + super(glWindow, null); + this.winHolder = winHolder; + } + + @Override + public void keyPressed(final KeyEvent e) { + if( e.isAutoRepeat() || e.isConsumed() ) { + return; + } + if( 0 == e.getModifiers() ) { // all modifiers go to super class .. + final int keySymbol = e.getKeySymbol(); + switch (keySymbol) { + case KeyEvent.VK_L: + e.setConsumed(true); + final com.jogamp.nativewindow.util.Point p0 = winHolder.getNativeWindow().getLocationOnScreen(null); + final com.jogamp.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); + printlnState("[location]", "Parent "+p0+", NEWT "+p1); + break; + case KeyEvent.VK_R: + e.setConsumed(true); + quitAdapterOff(); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + final java.lang.Thread t = glWindow.setExclusiveContextThread(null); + if(glWindow.getParent()==null) { + printlnState("[reparent pre - glWin to HOME: child pos "+winHolder.getNativeWindow().getX()+"/"+winHolder.getNativeWindow().getY()+"]"); + glWindow.reparentWindow(winHolder.getNativeWindow(), -1, -1, 0 /* hints */); + } else { + final com.jogamp.nativewindow.util.Point p0 = winHolder.getNativeWindow().getLocationOnScreen(null); + final com.jogamp.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); + printlnState("[reparent pre - glWin to TOP.1] frame ", p0+", glWindow "+p1); + glWindow.reparentWindow(null, p1.getX(), p1.getY(), 0 /* hint */); + } + printlnState("[reparent post]"); + glWindow.requestFocus(); + glWindow.setExclusiveContextThread(t); + quitAdapterOn(); + } } ); + break; + } + } + super.keyPressed(e); + } + + @Override + public void setTitle() { + setTitle(winHolder.getNativeWindow(), glWindow); + } + String getNativeWinTitle(final NativeWindow nw) { + return "["+nw.getX()+"/"+nw.getY()+" "+nw.getWidth()+"x"+nw.getHeight()+"], pix: "+nw.getSurfaceWidth()+"x"+nw.getSurfaceHeight(); + } + public void setTitle(final NativeWindow nw, final Window win) { + final CapabilitiesImmutable chosenCaps = win.getChosenCapabilities(); + final CapabilitiesImmutable reqCaps = win.getRequestedCapabilities(); + final CapabilitiesImmutable caps = null != chosenCaps ? chosenCaps : reqCaps; + final String capsA = caps.isBackgroundOpaque() ? "opaque" : "transl"; + final float[] sDPI = win.getPixelsPerMM(new float[2]); + sDPI[0] *= 25.4f; + sDPI[1] *= 25.4f; + win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]); + } +} 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 591ce5f4e..6e3c7c3e7 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 @@ -51,7 +51,8 @@ import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; public class TestParenting01NEWT extends UITestCase { static int width, height; static long durationPerTest = 600; - static long waitAbout10FramesAt30fps = 10*34; // 10 frames @ 30fps + static boolean manual = false; + static int loopVisibleToggle = 10; static GLCapabilities glCaps; @BeforeClass @@ -61,6 +62,37 @@ public class TestParenting01NEWT extends UITestCase { glCaps = new GLCapabilities(null); } + private static void waitForFrames(final String waitFor, final int prefixIdx, + final GLWindow glWindow1, final GLWindow glWindow2, + final long TO, final boolean doAssert) { + final long t0 = System.currentTimeMillis(); + int a, b; + long t1; + do { + try { Thread.sleep(16); } catch (final InterruptedException e) { } + if( null != glWindow1 ) { + a = glWindow1.getTotalFPSFrames(); + } else { + a = -1; + } + if( null != glWindow2 ) { + b = glWindow2.getTotalFPSFrames(); + } else { + b = -1; + } + t1 = System.currentTimeMillis(); + } while ( ( 0 == a || 0 == b ) && TO > ( t1 - t0 ) ); + System.err.println("Frames for "+waitFor+": A"+prefixIdx+": "+a+", B"+prefixIdx+": "+b); + if( doAssert ) { + if( null != glWindow1 ) { + Assert.assertTrue("No frames."+prefixIdx+" displayed on window1 during "+TO+"ms", 0 < a); + } + if( null != glWindow2 ) { + Assert.assertTrue("No frames."+prefixIdx+" displayed on window2 during "+TO+"ms", 0 < b); + } + } + } + @Test public void test01CreateVisibleDestroy() throws InterruptedException { Assert.assertEquals(0,Display.getActiveDisplayNumber()); @@ -109,44 +141,43 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(0,Display.getActiveDisplayNumber()); // visible test + for(int i=1; i<=loopVisibleToggle; i++) { + Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); + Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); + System.err.println("XXX VISIBLE."+i+" -> TRUE"); + glWindow1.setVisible(true); + Assert.assertEquals(true, glWindow1.isVisible()); + Assert.assertEquals(true, glWindow1.isNativeValid()); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeValid()); + Assert.assertEquals(1,display.getReferenceCount()); + Assert.assertEquals(true,display.isNativeValid()); + Assert.assertNotNull(display.getEDTUtil()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); + Assert.assertEquals(2,screen.getReferenceCount()); + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(1,Display.getActiveDisplayNumber()); + waitForFrames("window1.setVisible(true)", 1, glWindow1, glWindow2, 2000, true); + + System.err.println("XXX VISIBLE."+i+" -> FALSE"); + glWindow1.setVisible(false); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(true, glWindow1.isNativeValid()); + Assert.assertEquals(false, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeValid()); + + glWindow1.resetFPSCounter(); + glWindow2.resetFPSCounter(); + } Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); + System.err.println("XXX VISIBLE.3 -> TRUE"); glWindow1.setVisible(true); - System.err.println("Frames for setVisible(true): A1: "+glWindow1.getTotalFPSFrames()+", B1: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); - - Assert.assertEquals(true, glWindow1.isVisible()); - Assert.assertEquals(true, glWindow1.isNativeValid()); - Assert.assertEquals(true, glWindow2.isVisible()); - Assert.assertEquals(true, glWindow2.isNativeValid()); - Assert.assertEquals(1,display.getReferenceCount()); - Assert.assertEquals(true,display.isNativeValid()); - Assert.assertNotNull(display.getEDTUtil()); - Assert.assertEquals(true,display.getEDTUtil().isRunning()); - Assert.assertEquals(2,screen.getReferenceCount()); - Assert.assertEquals(true,screen.isNativeValid()); - Assert.assertEquals(1,Display.getActiveDisplayNumber()); - - glWindow1.setVisible(false); - Assert.assertEquals(false, glWindow1.isVisible()); - Assert.assertEquals(true, glWindow1.isNativeValid()); - Assert.assertEquals(false, glWindow2.isVisible()); - Assert.assertEquals(true, glWindow2.isNativeValid()); - - glWindow1.resetFPSCounter(); - glWindow2.resetFPSCounter(); - Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); - Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); - glWindow1.setVisible(true); - System.err.println("Frames for setVisible(true): A2: "+glWindow1.getTotalFPSFrames()+", B2: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); - Assert.assertEquals(true, glWindow1.isVisible()); Assert.assertEquals(true, glWindow1.isNativeValid()); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); + waitForFrames("window1.setVisible(true)", 2, glWindow1, glWindow2, 2000, true); glWindow1.resetFPSCounter(); glWindow2.resetFPSCounter(); @@ -165,9 +196,7 @@ public class TestParenting01NEWT extends UITestCase { while(animator1.isAnimating() && animator1.getTotalFPSDuration()<durationPerTest) { Thread.sleep(100); } - System.err.println("Frames for setVisible(true): A3: "+glWindow1.getTotalFPSFrames()+", B3: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("animator.start()", 3, glWindow1, glWindow2, 2000, true); Assert.assertEquals(true, animator1.pause()); Assert.assertEquals(false, animator1.isAnimating()); @@ -188,10 +217,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true, animator2.isAnimating()); Assert.assertEquals(false, animator2.isPaused()); Assert.assertNotNull(animator2.getThread()); - Thread.sleep(waitAbout10FramesAt30fps); - System.err.println("Frames for setVisible(true): A4: "+glWindow1.getTotalFPSFrames()+", B4: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("animator.resume()", 4, glWindow1, glWindow2, 2000, true); animator1.stop(); Assert.assertEquals(false, animator1.isAnimating()); @@ -243,15 +269,13 @@ public class TestParenting01NEWT extends UITestCase { glWindow2.resetFPSCounter(); Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); + System.err.println("XXX VISIBLE.4 -> TRUE"); glWindow1.setVisible(true); Assert.assertEquals(true, glWindow1.isVisible()); Assert.assertEquals(true, glWindow1.isNativeValid()); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); - - System.err.println("Frames for setVisible(true): A3: "+glWindow1.getTotalFPSFrames()+", B3: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("window1.setVisible(true) recreate", 5, glWindow1, glWindow2, 2000, true); Assert.assertEquals(1,display.getReferenceCount()); Assert.assertEquals(true,display.isNativeValid()); @@ -287,11 +311,17 @@ public class TestParenting01NEWT extends UITestCase { @Test public void test02aReparentTop2WinReparentRecreate() throws InterruptedException { + if( manual ) { + return; + } test02ReparentTop2WinImpl(true); } @Test public void test02bReparentTop2WinReparentNative() throws InterruptedException { + if( manual ) { + return; + } test02ReparentTop2WinImpl(false); } @@ -348,12 +378,10 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true,screen1.isNativeValid()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); Assert.assertEquals(true, glWindow1.isVisible()); - System.err.println("Frames for setVisible(true) A1: "+glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - + waitForFrames("window1.setVisible(true)", 1, glWindow1, null, 2000, true); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); - glWindow2.setVisible(true); + glWindow2.setVisible(true); Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); Assert.assertNotNull(display1.getEDTUtil()); @@ -362,8 +390,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true,screen1.isNativeValid()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); Assert.assertEquals(true, glWindow2.isVisible()); - System.err.println("Frames for setVisible(true) B1: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); + waitForFrames("window2.setVisible(true)", 2, glWindow1, glWindow2, 2000, true); final Animator animator1 = new Animator(glWindow1); animator1.setUpdateFPSFrames(1, null); @@ -405,9 +432,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); Assert.assertSame(glWindow1,glWindow2.getParent()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B2: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.child(parent, "+reparentRecreate+"), "+reparentAction, 10, glWindow1, glWindow2, 2000, true); Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); @@ -448,9 +473,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); Assert.assertNull(glWindow2.getParent()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B3: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.top(parent, "+reparentRecreate+"), "+reparentAction, 11, glWindow1, glWindow2, 2000, true); Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); @@ -523,11 +546,17 @@ public class TestParenting01NEWT extends UITestCase { @Test public void test03aReparentWin2TopReparentRecreate() throws InterruptedException { + if( manual ) { + return; + } test03ReparentWin2TopImpl(true); } @Test public void test03bReparentWin2TopReparentNative() throws InterruptedException { + if( manual ) { + return; + } test03ReparentWin2TopImpl(false); } @@ -579,10 +608,6 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); glWindow1.setVisible(true); - System.err.println("Frames for setVisible(): A1: "+glWindow1.getTotalFPSFrames()+", B1: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); Assert.assertNotNull(display1.getEDTUtil()); @@ -592,6 +617,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertSame(glWindow1,glWindow2.getParent()); Assert.assertSame(screen1,glWindow2.getScreen()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); + waitForFrames("window1.setVisible(true)", 1, glWindow1, glWindow2, 2000, true); final Animator animator1 = new Animator(glWindow1); animator1.setUpdateFPSFrames(1, null); @@ -630,9 +656,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertTrue(Window.ReparentOperation.ACTION_INVALID != reparentAction); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B2: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.top(parent, "+reparentRecreate+"), "+reparentAction, 10, glWindow1, glWindow2, 2000, true); Assert.assertNull(glWindow2.getParent()); Assert.assertSame(screen1,glWindow2.getScreen()); @@ -665,9 +689,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertTrue(Window.ReparentOperation.ACTION_INVALID != reparentAction); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B3 "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.child(parent, "+reparentRecreate+"), "+reparentAction, 11, glWindow1, glWindow2, 2000, true); Assert.assertSame(glWindow1,glWindow2.getParent()); Assert.assertSame(screen1,glWindow2.getScreen()); @@ -759,6 +781,10 @@ public class TestParenting01NEWT extends UITestCase { for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { durationPerTest = atoi(args[++i]); + } else if(args[i].equals("-loopvt")) { + loopVisibleToggle = atoi(args[++i]); + } else if(args[i].equals("-manual")) { + manual = true; } else if(args[i].equals("-asMain")) { asMain = true; } @@ -768,8 +794,8 @@ public class TestParenting01NEWT extends UITestCase { try { TestParenting01NEWT.initClass(); final TestParenting01NEWT m = new TestParenting01NEWT(); - m.test02aReparentTop2WinReparentRecreate(); m.test01CreateVisibleDestroy(); + m.test02aReparentTop2WinReparentRecreate(); } catch (final Throwable t ) { t.printStackTrace(); } 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 b53da38d7..4af752eb4 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 @@ -47,6 +47,7 @@ import javax.swing.WindowConstants; import com.jogamp.opengl.*; import com.jogamp.opengl.util.Animator; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.*; import com.jogamp.newt.opengl.*; import com.jogamp.newt.awt.NewtCanvasAWT; @@ -140,7 +141,7 @@ public class TestParenting01cSwingAWT extends UITestCase { animator1.start(); final GLDisturbanceAction disturbanceAction = new GLDisturbanceAction(glWindow1); - new Thread(disturbanceAction).start(); + new InterruptSource.Thread(null, disturbanceAction).start(); disturbanceAction.waitUntilRunning(); final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); @@ -274,7 +275,7 @@ public class TestParenting01cSwingAWT extends UITestCase { animator1.start(); final GLDisturbanceAction disturbanceAction = new GLDisturbanceAction(glWindow1); - new Thread(disturbanceAction).start(); + new InterruptSource.Thread(null, disturbanceAction).start(); disturbanceAction.waitUntilRunning(); final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); 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 6a7066820..b56010bc4 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 @@ -37,7 +37,8 @@ import org.junit.runners.MethodSorters; import com.jogamp.opengl.*; import com.jogamp.nativewindow.*; - +import com.jogamp.nativewindow.util.Point; +import com.jogamp.nativewindow.util.PointImmutable; import com.jogamp.newt.*; import com.jogamp.newt.event.*; import com.jogamp.newt.opengl.*; @@ -150,6 +151,7 @@ public class TestParenting02NEWT extends UITestCase { glWindow1.addGLEventListener(demo1); glWindow2.addGLEventListener(demo2); + glWindow2.addWindowListener(windowMoveDetection); boolean shouldQuit = false; long duration = durationPerTest; @@ -163,8 +165,19 @@ public class TestParenting02NEWT extends UITestCase { x += 1; y += 1; // glWindow1.setPosition(x,y); - glWindow2.setPosition(glWindow1.getWidth()/2,glWindow1.getHeight()/2-y); - Thread.sleep(step); + final PointImmutable expPos = new Point(glWindow1.getWidth()/2, glWindow1.getHeight()/2-y); + glWindow2.setPosition(expPos.getX(), expPos.getY()); + { + int waitCount=0; + do { + Thread.sleep(step); + waitCount++; + } while( !windowMoved && waitCount < 10); + final boolean didWindowMove = windowMoved; + windowMoved = false; + final PointImmutable hasPos = new Point(glWindow2.getX(), glWindow2.getY()); + System.err.println("Moved: exp "+expPos+", has "+hasPos+", equals "+expPos.equals(hasPos)+", didWindowMove "+didWindowMove+", waitCount "+waitCount); + } while( null != ( event = eventFifo.get() ) ) { final Window source = (Window) event.getSource(); @@ -186,6 +199,13 @@ public class TestParenting02NEWT extends UITestCase { destroyWindow(null, null, window2, glWindow2); destroyWindow(display, screen, window1, glWindow1); } + volatile boolean windowMoved = false; + final WindowListener windowMoveDetection = new WindowAdapter() { + @Override + public void windowMoved(final WindowEvent e) { + windowMoved = true; + } + }; public static void setDemoFields(final GLEventListener demo, final Window window, final GLWindow glWindow, final boolean debug) { Assert.assertNotNull(demo); @@ -214,17 +234,7 @@ public class TestParenting02NEWT extends UITestCase { } } final String tstname = TestParenting02NEWT.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/TestParenting03AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java index 723b84081..005839cec 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 @@ -47,6 +47,7 @@ import com.jogamp.opengl.*; import com.jogamp.opengl.util.Animator; import com.jogamp.newt.*; import com.jogamp.newt.opengl.*; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.newt.awt.NewtCanvasAWT; import java.io.IOException; @@ -54,6 +55,14 @@ import java.io.IOException; import com.jogamp.opengl.test.junit.util.*; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +/** + * <p> + * The demo code uses {@link NewtReparentingKeyAdapter} including {@link NEWTDemoListener} functionality. + * </p> + * <p> + * Manual invocation via main allows setting each tests's duration in milliseconds, e.g.{@code -duration 10000}, and many more, see {@link #main(String[])} + * </p> + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestParenting03AWT extends UITestCase { static Dimension glSize, fSize; @@ -88,7 +97,7 @@ public class TestParenting03AWT extends UITestCase { final GLEventListener demo1 = new GearsES2(1); setDemoFields(demo1, glWindow1, false); glWindow1.addGLEventListener(demo1); - glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1, null)); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); final GLAnimatorControl animator1 = new Animator(glWindow1); animator1.start(); @@ -104,7 +113,7 @@ public class TestParenting03AWT extends UITestCase { final GLEventListener demo2 = new GearsES2(1); setDemoFields(demo2, glWindow2, false); glWindow2.addGLEventListener(demo2); - glWindow2.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT2, glWindow2, null)); + glWindow2.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT2, glWindow2)); animator2 = new Animator(glWindow2); animator2.start(); } diff --git a/src/test/com/jogamp/opengl/test/junit/util/MiscUtils.java b/src/test/com/jogamp/opengl/test/junit/util/MiscUtils.java index 60f2f962c..bf656bb4d 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/MiscUtils.java +++ b/src/test/com/jogamp/opengl/test/junit/util/MiscUtils.java @@ -42,6 +42,7 @@ import java.util.List; import com.jogamp.opengl.GLContext; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; public class MiscUtils { public static boolean atob(final String str, final boolean def) { @@ -160,7 +161,7 @@ public class MiscUtils { return false; } - public static class StreamDump extends Thread { + public static class StreamDump extends InterruptSource.Thread { final InputStream is; final StringBuilder outString; final OutputStream outStream; |