aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java3
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowHolder.java41
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java291
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java12
-rw-r--r--src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java22
-rw-r--r--src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java670
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java38
-rw-r--r--src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java28
-rw-r--r--src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java10
-rw-r--r--src/newt/classes/jogamp/newt/javafx/JFXEDTUtil.java358
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java10
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java9
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NewtCanvasAWT.java32
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2SimpleNEWT.java10
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestLandscapeES2NewtCanvasAWT.java12
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java10
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/javafx/PureJFXApp01.java54
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/javafx/TestNewtCanvasJFXGLn.java516
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/event/TestParentingFocus03KeyTraversalAWT.java8
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java82
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtJFXReparentingKeyAdapter.java102
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtReparentingKeyAdapter.java111
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java9
23 files changed, 2333 insertions, 105 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
index ebd498401..323bc8c86 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java
@@ -42,6 +42,7 @@ 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;
@@ -733,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);
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/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/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/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/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/util/NEWTDemoListener.java b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
index 84c4683db..568b5d0bb 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java
@@ -34,6 +34,7 @@ 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;
@@ -47,12 +48,37 @@ 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;
+/**
+ * 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;
final PointerIcon[] pointerIcons;
@@ -230,12 +256,6 @@ public class NEWTDemoListener extends WindowAdapter implements KeyListener, Mous
printlnState("[set maximize post]", "max[vert "+vert+", horz "+horz+"]");
} } );
break;
- case KeyEvent.VK_Q:
- if( quitAdapterEnabled && 0 == e.getModifiers() ) {
- System.err.println("QUIT Key "+Thread.currentThread());
- quitAdapterShouldQuit = true;
- }
- break;
case KeyEvent.VK_P:
e.setConsumed(true);
glWindow.invokeOnNewThread(null, false, new Runnable() {
@@ -245,6 +265,12 @@ public class NEWTDemoListener extends WindowAdapter implements KeyListener, Mous
printlnState("[set position post]");
} } );
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);
glWindow.invokeOnNewThread(null, false, new Runnable() {
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/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
index 5194d9416..c30576ff4 100644
--- a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
+++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java
@@ -56,9 +56,13 @@ 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 &lt;applet&gt; tag. */
-
+/**
+ * Shows how to deploy an applet using JOGL.
+ * This demo must be referenced from a web page via an &lt;applet&gt; tag.
+ * <p>
+ * The demo code uses {@link NEWTDemoListener} functionality.
+ * </p>
+ */
public class JOGLNewtAppletBase implements KeyListener, GLEventListener {
public static final boolean DEBUG = Debug.debug("Applet");
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/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestOffscreenLayer02NewtCanvasAWT.java
index b052087a8..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
@@ -53,13 +53,23 @@ 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;
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 55b318d23..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
@@ -52,6 +52,7 @@ 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;
@@ -76,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;
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 4e60c4e95..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,6 +47,7 @@ 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;
@@ -54,6 +55,7 @@ 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;
@@ -73,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 };
@@ -81,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 };
@@ -247,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) { }
@@ -280,12 +294,6 @@ public class TestGearsES2NewtCanvasAWT extends UITestCase {
}
});
- final NewtAWTReparentingKeyAdapter newtDemoListener = new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow);
- newtDemoListener.quitAdapterEnable(true);
- glWindow.addKeyListener(newtDemoListener);
- glWindow.addMouseListener(newtDemoListener);
- glWindow.addWindowListener(newtDemoListener);
-
if( useAnimator ) {
animator.add(glWindow);
animator.start();
@@ -319,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
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 992d3c58e..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
@@ -47,7 +47,7 @@ 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);
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 d24113b8d..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,12 +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.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;
@@ -57,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);
@@ -112,7 +122,7 @@ public class TestLandscapeES2NewtCanvasAWT extends UITestCase {
}
});
- final NewtAWTReparentingKeyAdapter newtDemoListener = new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow);
+ final NewtReparentingKeyAdapter newtDemoListener = new NewtAWTReparentingKeyAdapter(frame, newtCanvasAWT, glWindow);
newtDemoListener.quitAdapterEnable(true);
glWindow.addKeyListener(newtDemoListener);
glWindow.addMouseListener(newtDemoListener);
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 3422aa091..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
@@ -36,7 +36,7 @@ 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;
@@ -47,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;
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/newt/event/TestParentingFocus03KeyTraversalAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/event/TestParentingFocus03KeyTraversalAWT.java
index b9be0ad9a..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 {
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 4fdee82c3..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,93 +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.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) {
- super(glWindow, 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();
- 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]");
- 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();
- } } );
- 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/TestParenting03AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java
index 73d41aefd..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;