diff options
Diffstat (limited to 'src/newt/classes/com')
11 files changed, 1382 insertions, 148 deletions
diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index 2ed2194d8..dd15eb3ea 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -59,6 +59,7 @@ public class NewtFactory { public static final String DRIVER_DEFAULT_ROOT_PACKAGE = "jogamp.newt.driver"; private static IOUtil.ClassResources defaultWindowIcons; + private static String sysPaths = "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"; static { AccessController.doPrivileged(new PrivilegedAction<Object>() { @@ -67,12 +68,11 @@ public class NewtFactory { NativeWindowFactory.initSingleton(); // last resort .. { /** See API Doc in {@link Window} ! */ - final String[] paths = PropertyAccess.getProperty("newt.window.icons", true, "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png").split("\\s"); + final String[] paths = PropertyAccess.getProperty("newt.window.icons", true, sysPaths).split("[\\s,]"); if( paths.length < 2 ) { throw new IllegalArgumentException("Property 'newt.window.icons' did not specify at least two PNG icons, but "+Arrays.toString(paths)); } - final Class<?> clazz = NewtFactory.class; - defaultWindowIcons = new IOUtil.ClassResources(clazz, paths); + defaultWindowIcons = new IOUtil.ClassResources(paths, NewtFactory.class.getClassLoader(), null); } return null; } } ); @@ -81,7 +81,7 @@ public class NewtFactory { /** * Returns the application window icon resources to be used. * <p> - * Property <code>newt.window.icons</code> may define a list of PNG icons separated by a whitespace character. + * Property <code>newt.window.icons</code> may define a list of PNG icons separated by one whitespace or one comma character. * Shall reference at least two PNG icons, from lower (16x16) to higher (>= 32x32) resolution. * </p> * <p> diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index d46afd1cd..30b02cb61 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -83,16 +83,22 @@ import com.jogamp.nativewindow.util.SurfaceSize; * <a name="customwindowicons"><h5>Custom Window Icons</h5></a> * <p> * Custom window icons can be defined via system property <code>newt.window.icons</code>, - * which shall contain a space separated list of PNG icon locations from low- to high-resolution. + * which shall contain a list of PNG icon locations from low- to high-resolution, + * separated by one whitespace or one comma character. * The location must be resolvable via classpath, i.e. shall reference a location within the jar file. * Example (our default): * <pre> - * -Dnewt.window.icons="newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png" - * -Djnlp.newt.window.icons="newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png" + * -Dnewt.window.icons="newt/data/jogamp-16x16.png,newt/data/jogamp-32x32.png" + * -Djnlp.newt.window.icons="newt/data/jogamp-16x16.png,newt/data/jogamp-32x32.png" * </pre> * The property can also be set programmatically, which must happen before any NEWT classes are <i>touched</i>: * <pre> - * System.setProperty("newt.window.icons", "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"); + * System.setProperty("newt.window.icons", "newt/data/jogamp-16x16.png, newt/data/jogamp-32x32.png"); + * </pre> + * To disable even Jogamp's own window icons in favor of system icons, + * simply set a non-existing location, e.g.: + * <pre> + * -Dnewt.window.icons="null,null" * </pre> * </p> * @@ -216,6 +222,10 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur public static final int STATE_BIT_MAXIMIZED_HORZ = 10; // reconfig-flag /** * Set if window is in <i>fullscreen mode</i>, otherwise cleared. + * <p> + * Usually fullscreen mode implies {@link #STATE_BIT_UNDECORATED}, + * however, an implementation is allowed to ignore this if unavailable. + * </p> * <p>Bit number {@value}.</p> * <p>Defaults to {@code false}.</p> * @see #getStateMask() @@ -223,9 +233,6 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur */ public static final int STATE_BIT_FULLSCREEN = 11; // reconfig-flag - // Hidden in WindowImpl: - // static final int STATE_BIT_FULLSCREEN_SPAN = 12; - /** * Set if the <i>pointer is visible</i> when inside the window, otherwise cleared. * <p>Bit number {@value}.</p> @@ -233,7 +240,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * @see #getStateMask() * @since 2.3.2 */ - public static final int STATE_BIT_POINTERVISIBLE = 13; + public static final int STATE_BIT_POINTERVISIBLE = 12; /** * Set if the <i>pointer is confined</i> to the window, otherwise cleared. * <p>Bit number {@value}.</p> @@ -241,7 +248,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * @see #getStateMask() * @since 2.3.2 */ - public static final int STATE_BIT_POINTERCONFINED = 14; + public static final int STATE_BIT_POINTERCONFINED = 13; /** * Bitmask for {@link #STATE_BIT_VISIBLE}, {@value}. @@ -330,6 +337,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur /** * Returns the current status mask of this instance. + * @see #getSupportedStateMask() * @see #STATE_MASK_VISIBLE * @see #STATE_MASK_AUTOPOSITION * @see #STATE_MASK_CHILDWIN @@ -354,6 +362,52 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur */ String getStateMaskString(); + /** + * Returns the supported {@link #getStateMask() state mask} of the implementation. + * <p> + * Implementation provides supported {@link #getStateMask() state mask} values at runtime + * <i>after</i> native window creation, i.e. first visibility. + * </p> + * <p> + * Please note that a window's size shall also be allowed to change, i.e. {@link #setSize(int, int)}. + * </p> + * <p> + * Default value is {@link #STATE_MASK_VISIBLE} | {@link #STATE_MASK_FOCUSED} | {@link #STATE_MASK_FULLSCREEN}, + * i.e. the <b>minimum requirement</b> for all implementations. + * </p> + * <p> + * Before native window creation {@link #getStatePublicBitmask()} is returned, + * i.e. it is assumed all features are supported. + * </p> + * <p> + * Semantic of the supported state-mask bits (after native creation, i.e. 1st visibility): + * <ul> + * <li>{@link #STATE_MASK_VISIBLE}: {@link #setVisible(boolean) Visibility} can be toggled. <b>Minimum requirement</b>.</li> + * <li>{@link #STATE_MASK_CHILDWIN}: {@link #reparentWindow(NativeWindow, int, int, int) Native window parenting} is supported.</li> + * <li>{@link #STATE_MASK_FOCUSED}: Window {@link #requestFocus() focus management} is supported. <b>Minimum requirement</b>.</li> + * <li>{@link #STATE_MASK_UNDECORATED}: {@link #setUndecorated(boolean) Window decoration} can be toggled.</li> + * <li>{@link #STATE_MASK_ALWAYSONTOP}: Window can be set {@link #setAlwaysOnTop(boolean) always-on-top}. </li> + * <li>{@link #STATE_MASK_ALWAYSONBOTTOM}: Window can be set {@link #setAlwaysOnBottom(boolean) always-on-bottom}. </li> + * <li>{@link #STATE_MASK_STICKY}: Window can be set {@link #setSticky(boolean) sticky}.</li> + * <li>{@link #STATE_MASK_RESIZABLE}: Window {@link #setResizable(boolean) resizability} can be toggled.</li> + * <li>{@link #STATE_MASK_MAXIMIZED_VERT}: Window can be {@link #setMaximized(boolean, boolean) maximized-vertically}. </li> + * <li>{@link #STATE_MASK_MAXIMIZED_HORZ}: Window can be {@link #setMaximized(boolean, boolean) maximized-horizontally}. </li> + * <li>{@link #STATE_MASK_FULLSCREEN}: Window {@link #setFullscreen(boolean) fullscreen} can be toggled. </li> + * <li>{@link #STATE_MASK_POINTERVISIBLE}: Window {@link #setPointerVisible(boolean) pointer visibility} can be toggled. </li> + * <li>{@link #STATE_MASK_POINTERCONFINED}: Window {@link #confinePointer(boolean) pointer can be confined}. </li> + * </ul> + * </p> + * @see #getStateMask() + * @since 2.3.2 + */ + int getSupportedStateMask(); + + /** + * Returns a string representation of the {@link #getSupportedStateMask() supported state mask}. + * @since 2.3.2 + */ + String getSupportedStateMaskString(); + // // Lifecycle // @@ -697,7 +751,6 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur boolean isSticky(); /** - * <p>Operation is ignored in {@link #isFullscreen() fullscreen mode}.</p> * <p>Operation is ignored if this instance {@link #isChildWindow() is a child window}.</p> * @see {@link #STATE_BIT_MAXIMIZED_HORZ} * @see {@link #STATE_BIT_MAXIMIZED_VERT} diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index ae32fd164..a0083b4ea 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -49,7 +49,9 @@ import java.security.PrivilegedAction; import java.util.Set; import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.NativeSurface; import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowHolder; import com.jogamp.nativewindow.OffscreenLayerOption; import com.jogamp.nativewindow.WindowClosingProtocol; import com.jogamp.opengl.GLAnimatorControl; @@ -100,7 +102,7 @@ import com.jogamp.opengl.util.TileRenderer; * the underlying JAWT mechanism to composite the image, if supported. */ @SuppressWarnings("serial") -public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol, OffscreenLayerOption, AWTPrintLifecycle { +public class NewtCanvasAWT extends java.awt.Canvas implements NativeWindowHolder, WindowClosingProtocol, OffscreenLayerOption, AWTPrintLifecycle { public static final boolean DEBUG = Debug.debug("Window"); private final Object sync = new Object(); @@ -110,7 +112,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto private Window newtChild = null; private boolean newtChildAttached = false; private boolean isOnscreen = true; - private WindowClosingMode newtChildCloseOp; + private WindowClosingMode newtChildCloseOp = WindowClosingMode.DISPOSE_ON_CLOSE; private final AWTParentWindowAdapter awtWinAdapter; private final AWTAdapter awtMouseAdapter; private final AWTAdapter awtKeyAdapter; @@ -420,10 +422,22 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto return newtChild; } - /** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called, - * or {@link #addNotify()} hasn't been called yet.*/ + /** + * {@inheritDoc} + * @return this AWT Canvas {@link NativeWindow} representation, may be null in case {@link #removeNotify()} has been called, + * or {@link #addNotify()} hasn't been called yet. + */ + @Override public NativeWindow getNativeWindow() { return jawtWindow; } + /** + * {@inheritDoc} + * @return this AWT Canvas {@link NativeSurface} representation, may be null in case {@link #removeNotify()} has been called, + * or {@link #addNotify()} hasn't been called yet. + */ + @Override + public NativeSurface getNativeSurface() { return jawtWindow; } + @Override public WindowClosingMode getDefaultCloseOperation() { return awtWindowClosingProtocol.getDefaultCloseOperation(); diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java index cd53294a1..6bf9f41a6 100644 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java @@ -115,7 +115,7 @@ public class JOGLNewtApplet1Run extends Applet { String glEventListenerClazzName=null; String glProfileName=null; - int glSwapInterval=0; + int glSwapInterval=1; boolean glDebug=false; boolean glTrace=false; boolean glUndecorated=false; diff --git a/src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java b/src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java new file mode 100644 index 000000000..e04ed326d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/javafx/NewtCanvasJFX.java @@ -0,0 +1,670 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.newt.javafx; + +import com.jogamp.common.util.PropertyAccess; +import com.jogamp.nativewindow.AbstractGraphicsConfiguration; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.Capabilities; +import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.GraphicsConfigurationFactory; +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.NativeWindowHolder; +import com.jogamp.nativewindow.SurfaceUpdatedListener; +import com.jogamp.nativewindow.WindowClosingProtocol; +import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode; +import com.jogamp.nativewindow.util.Insets; +import com.jogamp.nativewindow.util.InsetsImmutable; +import com.jogamp.nativewindow.util.Point; +import com.jogamp.nativewindow.util.Rectangle; +import com.jogamp.opengl.GLCapabilities; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.EventHandler; +import javafx.geometry.Bounds; +import javafx.scene.Scene; +import javafx.scene.canvas.Canvas; +import jogamp.newt.Debug; +import jogamp.newt.javafx.JFXEDTUtil; + +import com.jogamp.nativewindow.javafx.JFXAccessor; +import com.jogamp.newt.Display; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.util.EDTUtil; + +/** + * A NEWT based JFX {@link Canvas} specialization allowing a NEWT child {@link Window} to be attached using native parenting. + * <p> + * {@link NewtCanvasJFX} allows utilizing custom {@link GLCapabilities} settings independent from the JavaFX's window + * as well as independent rendering from JavaFX's thread. + * </p> + * <p> + * {@link NewtCanvasJFX} allows native parenting operations before and after + * it's belonging Group's Scene has been attached to the JavaFX {@link javafx.stage.Window Window}'s actual native window, + * i.e. becoming fully realized and visible. + * </p> + * <p> + * Note that {@link JFXAccessor#runOnJFXThread(boolean, Runnable)} is still used to for certain + * mandatory JavaFX lifecycle operation on the JavaFX thread. + * </p> + */ +public class NewtCanvasJFX extends Canvas implements NativeWindowHolder, WindowClosingProtocol { + private static final boolean DEBUG = Debug.debug("Window"); + private static final boolean USE_JFX_EDT = PropertyAccess.getBooleanProperty("jogamp.newt.javafx.UseJFXEDT", true, true); + private volatile javafx.stage.Window parentWindow = null; + private volatile AbstractGraphicsScreen screen = null; + + private WindowClosingMode newtChildClosingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private WindowClosingMode closingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private final Rectangle clientArea = new Rectangle(); + + private volatile JFXNativeWindow nativeWindow = null; + private volatile Window newtChild = null; + private volatile boolean newtChildReady = false; // ready if JFXEDTUtil is set and newtChild parented + private volatile boolean postSetSize = false; // pending resize + private volatile boolean postSetPos = false; // pending pos + + private final EventHandler<javafx.stage.WindowEvent> windowClosingListener = new EventHandler<javafx.stage.WindowEvent>() { + public final void handle(final javafx.stage.WindowEvent e) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.DISPOSE, "+e+", closeOp "+closingMode); + } + if( WindowClosingMode.DISPOSE_ON_CLOSE == closingMode ) { + NewtCanvasJFX.this.destroy(); + } else { + // avoid JavaFX closing operation + e.consume(); + } + } }; + private final EventHandler<javafx.stage.WindowEvent> windowShownListener = new EventHandler<javafx.stage.WindowEvent>() { + public final void handle(final javafx.stage.WindowEvent e) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.SHOWN, "+e); + } + repaintAction(true); + } }; + + /** + * Instantiates a NewtCanvas with a NEWT child. + * + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an JFX conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * @param child optional preassigned {@link #Window}, maybe null + */ + public NewtCanvasJFX(final Window child) { + super(); + + updateParentWindowAndScreen(); + + final ChangeListener<Number> sizeListener = new ChangeListener<Number>() { + @Override public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Size, "+oldValue.doubleValue()+" -> "+newValue.doubleValue()+", has "+getWidth()+"x"+getHeight()); + } + updateSizeCheck((int)getWidth(), (int)getHeight()); + repaintAction(isVisible()); + } }; + this.widthProperty().addListener(sizeListener); + this.heightProperty().addListener(sizeListener); + this.visibleProperty().addListener(new ChangeListener<Boolean>() { + @Override public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue, final Boolean newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Visible, "+oldValue.booleanValue()+" -> "+newValue.booleanValue()+", has "+isVisible()); + } + repaintAction(newValue.booleanValue()); + } + }); + this.sceneProperty().addListener(new ChangeListener<Scene>() { + @Override public void changed(final ObservableValue<? extends Scene> observable, final Scene oldValue, final Scene newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Scene, "+oldValue+" -> "+newValue+", has "+getScene()); + if(null != newValue) { + final javafx.stage.Window w = newValue.getWindow(); + System.err.println("NewtCanvasJFX.Event.Scene window "+w+" (showing "+(null!=w?w.isShowing():0)+")"); + } + } + if( updateParentWindowAndScreen() ) { + repaintAction(isVisible()); + } + } + }); + + if(null != child) { + setNEWTChild(child); + } + } + + private final void repaintAction(final boolean visible) { + if( visible && ( null != nativeWindow || validateNative(true /* completeReparent */) ) ) { + if( newtChildReady ) { + if( postSetSize ) { + newtChild.setSize(clientArea.getWidth(), clientArea.getHeight()); + postSetSize = false; + } + if( postSetPos ) { + newtChild.setPosition(clientArea.getX(), clientArea.getY()); + postSetPos = false; + } + newtChild.windowRepaint(0, 0, clientArea.getWidth(), clientArea.getHeight()); + } + } + } + + private final void updatePosSizeCheck() { + final Bounds b = localToScene(getBoundsInLocal()); + updatePosCheck((int)b.getMinX(), (int)b.getMinY()); + updateSizeCheck((int)getWidth(), (int)getHeight()); + } + private final void updatePosCheck(final int newX, final int newY) { + final boolean posChanged; + { + final Rectangle oClientArea = clientArea; + posChanged = newX != oClientArea.getX() || newY != oClientArea.getY(); + if( posChanged ) { + clientArea.setX(newX); + clientArea.setY(newY); + } + } + if(DEBUG) { + final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; + System.err.println("NewtCanvasJFX.updatePosCheck: posChanged "+posChanged+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+clientArea.getX()+"/"+clientArea.getY()+" "+clientArea.getWidth()+"x"+clientArea.getHeight()+" - surfaceHandle 0x"+Long.toHexString(nsh)); + } + if( posChanged ) { + if( newtChildReady ) { + newtChild.setPosition(clientArea.getX(), clientArea.getY()); + } else { + postSetPos = true; + } + } + } + private final void updateSizeCheck(final int newWidth, final int newHeight) { + final boolean sizeChanged; + { + final Rectangle oClientArea = clientArea; + sizeChanged = newWidth != oClientArea.getWidth() || newHeight != oClientArea.getHeight(); + if( sizeChanged ) { + clientArea.setWidth(newWidth); + clientArea.setHeight(newHeight); + } + } + if(DEBUG) { + final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; + System.err.println("NewtCanvasJFX.updateSizeCheck: sizeChanged "+sizeChanged+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+clientArea.getX()+"/"+clientArea.getY()+" "+clientArea.getWidth()+"x"+clientArea.getHeight()+" - surfaceHandle 0x"+Long.toHexString(nsh)); + } + if( sizeChanged ) { + if( newtChildReady ) { + newtChild.setSize(clientArea.getWidth(), clientArea.getHeight()); + } else { + postSetSize = true; + } + } + } + + private final ChangeListener<javafx.stage.Window> sceneWindowChangeListener = new ChangeListener<javafx.stage.Window>() { + @Override public void changed(final ObservableValue<? extends javafx.stage.Window> observable, final javafx.stage.Window oldValue, final javafx.stage.Window newValue) { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.Event.Window, "+oldValue+" -> "+newValue); + } + if( updateParentWindowAndScreen() ) { + repaintAction(isVisible()); + } + } }; + + private boolean updateParentWindowAndScreen() { + final Scene s = this.getScene(); + if( null != s ) { + final javafx.stage.Window w = s.getWindow(); + if( DEBUG ) { + System.err.println("NewtCanvasJFX.updateParentWindowAndScreen: Scene "+s+", Window "+w+" (showing "+(null!=w?w.isShowing():0)+")"); + } + if( w != parentWindow ) { + destroyImpl(false); + } + parentWindow = w; + if( null != w ) { + screen = JFXAccessor.getScreen(JFXAccessor.getDevice(parentWindow), -1 /* default */); + parentWindow.addEventHandler(javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST, windowClosingListener); + parentWindow.addEventHandler(javafx.stage.WindowEvent.WINDOW_SHOWN, windowShownListener); + return true; + } else { + s.windowProperty().addListener(sceneWindowChangeListener); + } + } else { + if( DEBUG ) { + System.err.println("NewtCanvasJFX.updateParentWindowAndScreen: Null Scene"); + } + if( null != parentWindow ) { + destroyImpl(false); + } + } + return false; + } + + /** + * Destroys this resource: + * <ul> + * <li> Make the NEWT Child invisible </li> + * <li> Disconnects the NEWT Child from this Canvas NativeWindow, reparent to NULL </li> + * <li> Issues {@link Window#destroy()} on the NEWT Child</li> + * <li> Remove reference to the NEWT Child</li> + * </ul> + * JavaFX will issue this call when sending out the {@link javafx.stage.WindowEvent#WINDOW_CLOSE_REQUEST} automatically, + * if the user has not overridden the default {@link WindowClosingMode#DISPOSE_ON_CLOSE} to {@link WindowClosingMode#DO_NOTHING_ON_CLOSE} + * via {@link #setDefaultCloseOperation(com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode)}. + * @see Window#destroy() + * @see #setDefaultCloseOperation(com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode) + */ + public void destroy() { + destroyImpl(true); + } + private void destroyImpl(final boolean disposeNewtChild) { + if(DEBUG) { + System.err.println("NewtCanvasJFX.dispose: (has parent "+(null!=parentWindow)+", hasNative "+(null!=nativeWindow)+",\n\t"+newtChild); + } + if( null != newtChild ) { + if(DEBUG) { + System.err.println("NewtCanvasJFX.dispose.1: EDTUtil cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + if( null != nativeWindow ) { + configureNewtChild(false); + newtChild.setVisible(false); + newtChild.reparentWindow(null, -1, -1, 0 /* hint */); + } + if( disposeNewtChild ) { + newtChild.destroy(); + newtChild = null; + } + } + if( null != parentWindow ) { + parentWindow.getScene().windowProperty().removeListener(sceneWindowChangeListener); + parentWindow.removeEventHandler(javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST, windowClosingListener); + parentWindow.removeEventHandler(javafx.stage.WindowEvent.WINDOW_SHOWN, windowShownListener); + parentWindow = null; + } + if( null != screen ) { + screen.getDevice().close(); + screen = null; + } + nativeWindow = null; + } + + private final boolean validateNative(final boolean completeReparent) { + if( null == parentWindow ) { + return false; + } + assert null == nativeWindow; + updatePosSizeCheck(); + if(0 >= clientArea.getWidth() || 0 >= clientArea.getHeight()) { + return false; + } + final long nativeWindowHandle = JFXAccessor.getWindowHandle(parentWindow); + if( 0 == nativeWindowHandle ) { + return false; + } + screen.getDevice().open(); + + /* Native handle for the control, used to associate with GLContext */ + final int visualID = JFXAccessor.getNativeVisualID(screen.getDevice(), nativeWindowHandle); + final boolean visualIDValid = NativeWindowFactory.isNativeVisualIDValidForProcessing(visualID); + if(DEBUG) { + System.err.println("NewtCanvasJFX.validateNative() windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", valid "+visualIDValid); + } + if( visualIDValid ) { + /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite). + * Note: JFX is owner of the native handle, hence no closing operation will be a NOP. */ + final CapabilitiesImmutable caps = new Capabilities(); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(screen.getDevice(), caps); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration( caps, caps, null, screen, visualID ); + if(DEBUG) { + System.err.println("NewtCanvasJFX.validateNative() factory: "+factory+", windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", chosen config: "+config); + // Thread.dumpStack(); + } + if (null == config) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + nativeWindow = new JFXNativeWindow(config, nativeWindowHandle); + if( completeReparent ) { + reparentWindow( true ); + } + } + + return null != nativeWindow; + } + + /** + * Sets a new NEWT child, provoking reparenting. + * <p> + * A previously detached <code>newChild</code> will be released to top-level status + * and made invisible. + * </p> + * <p> + * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code> + * produced much cleaner visual results. + * </p> + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an JFX conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * @return the previous attached newt child. + */ + public Window setNEWTChild(final Window newChild) { + final Window prevChild = newtChild; + if(DEBUG) { + System.err.println("NewtCanvasJFX.setNEWTChild.0: win "+newtWinHandleToHexString(prevChild)+" -> "+newtWinHandleToHexString(newChild)); + } + // remove old one + if(null != newtChild) { + reparentWindow( false ); + newtChild = null; + } + // add new one, reparent only if ready + newtChild = newChild; + if( null != newtChild && ( null != nativeWindow || validateNative(false /* completeReparent */) ) ) { + reparentWindow( true ); + } + return prevChild; + } + + private void reparentWindow(final boolean add) { + if( null == newtChild ) { + return; // nop + } + if(DEBUG) { + System.err.println("NewtCanvasJFX.reparentWindow.0: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + + newtChild.setFocusAction(null); // no AWT focus traversal .. + if(add) { + assert null != nativeWindow && null != parentWindow; + updatePosSizeCheck(); + final int x = clientArea.getX(); + final int y = clientArea.getY(); + final int w = clientArea.getWidth(); + final int h = clientArea.getHeight(); + + if(USE_JFX_EDT) { + // setup JFX EDT and start it + final Display newtDisplay = newtChild.getScreen().getDisplay(); + final EDTUtil oldEDTUtil = newtDisplay.getEDTUtil(); + if( ! ( oldEDTUtil instanceof JFXEDTUtil ) ) { + final EDTUtil newEDTUtil = new JFXEDTUtil(newtDisplay); + if(DEBUG) { + System.err.println("NewtCanvasJFX.reparentWindow.1: replacing EDTUtil "+oldEDTUtil+" -> "+newEDTUtil); + } + newEDTUtil.start(); + newtDisplay.setEDTUtil( newEDTUtil ); + } + } + + newtChild.setSize(w, h); + newtChild.reparentWindow(nativeWindow, x, y, Window.REPARENT_HINT_BECOMES_VISIBLE); + newtChild.setPosition(x, y); + newtChild.setVisible(true); + configureNewtChild(true); + newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener + + // force this JFX Canvas to be focus-able, + // since it is completely covered by the newtChild (z-order). + // FIXME ??? super.requestFocus(); + } else { + configureNewtChild(false); + newtChild.setVisible(false); + newtChild.reparentWindow(null, -1, -1, 0 /* hints */); + } + if(DEBUG) { + System.err.println("NewtCanvasJFX.reparentWindow.X: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + } + + private void configureNewtChild(final boolean attach) { + newtChildReady = attach; + if( null != newtChild ) { + newtChild.setKeyboardFocusHandler(null); + if(attach) { + newtChildClosingMode = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE); + } else { + newtChild.setFocusAction(null); + newtChild.setDefaultCloseOperation(newtChildClosingMode); + } + } + } + + /** @return the current NEWT child */ + public Window getNEWTChild() { + return newtChild; + } + + /** + * {@inheritDoc} + * @return this JFX Canvas {@link NativeWindow} representation, may be null in case it has not been realized + */ + @Override + public NativeWindow getNativeWindow() { return nativeWindow; } + + /** + * {@inheritDoc} + * @return this JFX Canvas {@link NativeSurface} representation, may be null in case it has not been realized + */ + @Override + public NativeSurface getNativeSurface() { return nativeWindow; } + + @Override + public WindowClosingMode getDefaultCloseOperation() { + return closingMode; + } + + @Override + public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) { + final WindowClosingMode old = closingMode; + closingMode = op; + return old; + } + + + boolean isParent() { + return null!=newtChild ; + } + + boolean isFullscreen() { + return null != newtChild && newtChild.isFullscreen(); + } + + private final void requestFocusNEWTChild() { + if( newtChildReady ) { + newtChild.setFocusAction(null); + newtChild.requestFocus(); + } + } + + @Override + public void requestFocus() { + NewtCanvasJFX.super.requestFocus(); + requestFocusNEWTChild(); + } + + private class JFXNativeWindow implements NativeWindow { + private final AbstractGraphicsConfiguration config; + private final long nativeWindowHandle; + private final InsetsImmutable insets; // only required to allow proper client position calculation on OSX + + public JFXNativeWindow(final AbstractGraphicsConfiguration config, final long nativeWindowHandle) { + this.config = config; + this.nativeWindowHandle = nativeWindowHandle; + this.insets = new Insets(0, 0, 0, 0); + } + + @Override + public int lockSurface() throws NativeWindowException, RuntimeException { + return NativeSurface.LOCK_SUCCESS; + } + + @Override + public void unlockSurface() { } + + @Override + public boolean isSurfaceLockedByOtherThread() { + return false; + } + + @Override + public Thread getSurfaceLockOwner() { + return null; + } + + @Override + public boolean surfaceSwap() { + return false; + } + + @Override + public void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { } + + @Override + public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + } + + @Override + public void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { } + + @Override + public long getSurfaceHandle() { + return 0; + } + + @Override + public int getWidth() { + return getSurfaceWidth(); // FIXME: Use 'scale' or an actual window-width + } + + @Override + public int getHeight() { + return getSurfaceHeight(); // FIXME: Use 'scale' or an actual window-width + } + + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + return pixelUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + } + + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + return windowUnitsAndResult; // FIXME HiDPI: use 'pixelScale' + } + + @Override + public int getSurfaceWidth() { + return clientArea.getWidth(); + } + + @Override + public int getSurfaceHeight() { + return clientArea.getHeight(); + } + + @Override + public final NativeSurface getNativeSurface() { return this; } + + @Override + public AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config; + } + + @Override + public long getDisplayHandle() { + return config.getScreen().getDevice().getHandle(); + } + + @Override + public int getScreenIndex() { + return config.getScreen().getIndex(); + } + + @Override + public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { } + + @Override + public void destroy() { } + + @Override + public NativeWindow getParent() { + return null; + } + + @Override + public long getWindowHandle() { + return nativeWindowHandle; + } + + @Override + public InsetsImmutable getInsets() { + return insets; + } + + @Override + public int getX() { + return NewtCanvasJFX.this.clientArea.getX(); + } + + @Override + public int getY() { + return NewtCanvasJFX.this.clientArea.getY(); + } + + @Override + public Point getLocationOnScreen(final Point point) { + final Point los = NativeWindowFactory.getLocationOnScreen(this); // client window location on screen + if(null!=point) { + return point.translate(los); + } else { + return los; + } + } + + @Override + public boolean hasFocus() { + return isFocused(); + } + }; + + static String newtWinHandleToHexString(final Window w) { + return null != w ? toHexString(w.getWindowHandle()) : "nil"; + } + static String toHexString(final long l) { + return "0x"+Long.toHexString(l); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index f15c87beb..569780311 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -246,6 +246,16 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind } @Override + public final int getSupportedStateMask() { + return window.getSupportedStateMask(); + } + + @Override + public final String getSupportedStateMaskString() { + return window.getSupportedStateMaskString(); + } + + @Override public CapabilitiesChooser setCapabilitiesChooser(final CapabilitiesChooser chooser) { return window.setCapabilitiesChooser(chooser); } diff --git a/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java new file mode 100644 index 000000000..568b5d0bb --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/opengl/util/NEWTDemoListener.java @@ -0,0 +1,530 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.newt.opengl.util; + +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.common.util.IOUtil; +import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.ScalableSurface; +import com.jogamp.newt.Window; +import com.jogamp.newt.Display; +import com.jogamp.newt.Display.PointerIcon; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.FPSCounter; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLDrawable; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.util.Gamma; +import com.jogamp.opengl.util.PNGPixelRect; + +import jogamp.newt.driver.PNGIcon; + +/** + * 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; + int pointerIconIdx = 0; + float gamma = 1f; + float brightness = 0f; + float contrast = 1f; + boolean confinedFixedCenter = false; + + public NEWTDemoListener(final GLWindow glWin, final PointerIcon[] pointerIcons) { + this.glWindow = glWin; + if( null != pointerIcons ) { + this.pointerIcons = pointerIcons; + } else { + this.pointerIcons = createPointerIcons(glWindow.getScreen().getDisplay()); + } + } + public NEWTDemoListener(final GLWindow glWin) { + this(glWin, null); + } + + protected void printlnState(final String prelude) { + System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString()); + } + protected void printlnState(final String prelude, final String post) { + System.err.println(prelude+": "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets()+", state "+glWindow.getStateMaskString()+", "+post); + } + + @Override + public void keyPressed(final KeyEvent e) { + if( e.isAutoRepeat() || e.isConsumed() ) { + return; + } + final int keySymbol = e.getKeySymbol(); + switch(keySymbol) { + case KeyEvent.VK_SPACE: + e.setConsumed(true); + glWindow.invokeOnCurrentThread(new Runnable() { + public void run() { + if(glWindow.getAnimator().isPaused()) { + glWindow.getAnimator().resume(); + } else { + glWindow.getAnimator().pause(); + } + } } ); + break; + case KeyEvent.VK_A: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set alwaysontop pre]"); + glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop()); + printlnState("[set alwaysontop post]"); + } } ); + break; + case KeyEvent.VK_B: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set alwaysonbottom pre]"); + glWindow.setAlwaysOnBottom(!glWindow.isAlwaysOnBottom()); + printlnState("[set alwaysonbottom post]"); + } } ); + break; + case KeyEvent.VK_C: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + if( null != pointerIcons ) { + printlnState("[set pointer-icon pre]"); + final PointerIcon currentPI = glWindow.getPointerIcon(); + final PointerIcon newPI; + if( pointerIconIdx >= pointerIcons.length ) { + newPI=null; + pointerIconIdx=0; + } else { + newPI=pointerIcons[pointerIconIdx++]; + } + glWindow.setPointerIcon( newPI ); + printlnState("[set pointer-icon post]", currentPI+" -> "+glWindow.getPointerIcon()); + } + } } ); + break; + case KeyEvent.VK_D: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set undecorated pre]"); + glWindow.setUndecorated(!glWindow.isUndecorated()); + printlnState("[set undecorated post]"); + } } ); + break; + case KeyEvent.VK_F: + e.setConsumed(true); + quitAdapterOff(); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set fullscreen pre]"); + if( glWindow.isFullscreen() ) { + glWindow.setFullscreen( false ); + } else { + if( e.isAltDown() ) { + glWindow.setFullscreen( null ); + } else { + glWindow.setFullscreen( true ); + } + } + printlnState("[set fullscreen post]"); + quitAdapterOn(); + } } ); + break; + case KeyEvent.VK_G: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + final float newGamma = gamma + ( e.isShiftDown() ? -0.1f : 0.1f ); + System.err.println("[set gamma]: "+gamma+" -> "+newGamma); + if( Gamma.setDisplayGamma(glWindow, newGamma, brightness, contrast) ) { + gamma = newGamma; + } + } } ); + break; + case KeyEvent.VK_I: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set pointer-visible pre]"); + glWindow.setPointerVisible(!glWindow.isPointerVisible()); + printlnState("[set pointer-visible post]"); + } } ); + break; + case KeyEvent.VK_J: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set pointer-confined pre]", "warp-center: "+e.isShiftDown()); + final boolean confine = !glWindow.isPointerConfined(); + glWindow.confinePointer(confine); + printlnState("[set pointer-confined post]", "warp-center: "+e.isShiftDown()); + if( e.isShiftDown() ) { + setConfinedFixedCenter(confine); + } else if( !confine ) { + setConfinedFixedCenter(false); + } + } } ); + break; + case KeyEvent.VK_M: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + // none: max-v + // alt: max-h + // shift: max-hv + // ctrl: max-off + final boolean horz, vert; + if( e.isControlDown() ) { + horz = false; + vert = false; + } else if( e.isShiftDown() ) { + final boolean bothMax = glWindow.isMaximizedHorz() && glWindow.isMaximizedVert(); + horz = !bothMax; + vert = !bothMax; + } else if( !e.isAltDown() ) { + horz = glWindow.isMaximizedHorz(); + vert = !glWindow.isMaximizedVert(); + } else if( e.isAltDown() ) { + horz = !glWindow.isMaximizedHorz(); + vert = glWindow.isMaximizedVert(); + } else { + vert = glWindow.isMaximizedVert(); + horz = glWindow.isMaximizedHorz(); + } + printlnState("[set maximize pre]", "max[vert "+vert+", horz "+horz+"]"); + glWindow.setMaximized(horz, vert); + printlnState("[set maximize post]", "max[vert "+vert+", horz "+horz+"]"); + } } ); + break; + case KeyEvent.VK_P: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set position pre]"); + glWindow.setPosition(100, 100); + 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() { + public void run() { + printlnState("[set resizable pre]"); + glWindow.setResizable(!glWindow.isResizable()); + printlnState("[set resizable post]"); + } } ); + break; + case KeyEvent.VK_S: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set sticky pre]"); + glWindow.setSticky(!glWindow.isSticky()); + printlnState("[set sticky post]"); + } } ); + break; + case KeyEvent.VK_V: + e.setConsumed(true); + if( e.isControlDown() ) { + glWindow.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = -1; break; + case -1: i = 1; break; + case 1: i = 0; break; + default: i = 1; break; + } + gl.setSwapInterval(i); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + if(drawable instanceof FPSCounter) { + ((FPSCounter)drawable).resetFPSCounter(); + } + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); + return true; + } + }); + } else { + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + final boolean wasVisible = glWindow.isVisible(); + { + printlnState("[set visible pre]"); + glWindow.setVisible(!wasVisible); + printlnState("[set visible post]"); + } + if( wasVisible && !e.isShiftDown() ) { + try { + java.lang.Thread.sleep(5000); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + printlnState("[reset visible pre]"); + glWindow.setVisible(true); + printlnState("[reset visible post]"); + } + } } ); + } + break; + case KeyEvent.VK_W: + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { + public void run() { + printlnState("[set pointer-pos pre]"); + glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2); + printlnState("[set pointer-pos post]"); + } } ); + break; + case KeyEvent.VK_X: + e.setConsumed(true); + final float[] hadSurfacePixelScale = glWindow.getCurrentSurfaceScale(new float[2]); + final float[] reqSurfacePixelScale; + if( hadSurfacePixelScale[0] == ScalableSurface.IDENTITY_PIXELSCALE ) { + reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + } else { + reqSurfacePixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + } + System.err.println("[set PixelScale pre]: had "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" -> req "+reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]); + glWindow.setSurfaceScale(reqSurfacePixelScale); + final float[] valReqSurfacePixelScale = glWindow.getRequestedSurfaceScale(new float[2]); + final float[] hasSurfacePixelScale1 = glWindow.getCurrentSurfaceScale(new float[2]); + System.err.println("[set PixelScale post]: "+hadSurfacePixelScale[0]+"x"+hadSurfacePixelScale[1]+" (had) -> "+ + reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" (req) -> "+ + valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ + hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); + setTitle(); + } + } + @Override + public void keyReleased(final KeyEvent e) { } + + public void setConfinedFixedCenter(final boolean v) { + confinedFixedCenter = v; + } + @Override + public void mouseMoved(final MouseEvent e) { + if( e.isConfined() ) { + mouseCenterWarp(e); + } + } + @Override + public void mouseDragged(final MouseEvent e) { + if( e.isConfined() ) { + mouseCenterWarp(e); + } + } + @Override + public void mouseClicked(final MouseEvent e) { + if(e.getClickCount() == 2 && e.getPointerCount() == 3) { + glWindow.setFullscreen(!glWindow.isFullscreen()); + System.err.println("setFullscreen: "+glWindow.isFullscreen()); + } + } + private void mouseCenterWarp(final MouseEvent e) { + if(e.isConfined() && confinedFixedCenter ) { + final int x=glWindow.getSurfaceWidth()/2; + final int y=glWindow.getSurfaceHeight()/2; + glWindow.warpPointer(x, y); + } + } + @Override + public void mouseEntered(final MouseEvent e) {} + @Override + public void mouseExited(final MouseEvent e) {} + @Override + public void mousePressed(final MouseEvent e) {} + @Override + public void mouseReleased(final MouseEvent e) {} + @Override + public void mouseWheelMoved(final MouseEvent e) {} + + ///////////////////////////////////////////////////////////// + + private boolean quitAdapterShouldQuit = false; + private boolean quitAdapterEnabled = false; + private boolean quitAdapterEnabled2 = true; + + protected void quitAdapterOff() { + quitAdapterEnabled2 = false; + } + protected void quitAdapterOn() { + clearQuitAdapter(); + quitAdapterEnabled2 = true; + } + public void quitAdapterEnable(final boolean v) { quitAdapterEnabled = v; } + public void clearQuitAdapter() { quitAdapterShouldQuit = false; } + public boolean shouldQuit() { return quitAdapterShouldQuit; } + public void doQuit() { quitAdapterShouldQuit=true; } + + public void windowDestroyNotify(final WindowEvent e) { + if( quitAdapterEnabled && quitAdapterEnabled2 ) { + System.err.println("QUIT Window "+Thread.currentThread()); + quitAdapterShouldQuit = true; + } + } + + ///////////////////////////////////////////////////////////// + + public void setTitle() { + setTitle(glWindow); + } + public static void setTitle(final GLWindow 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; + final float[] minSurfacePixelScale = win.getMinimumSurfaceScale(new float[2]); + final float[] maxSurfacePixelScale = win.getMaximumSurfaceScale(new float[2]); + final float[] reqSurfacePixelScale = win.getRequestedSurfaceScale(new float[2]); + final float[] hasSurfacePixelScale = win.getCurrentSurfaceScale(new float[2]); + win.setTitle("GLWindow["+capsA+"], win: "+win.getBounds()+", pix: "+win.getSurfaceWidth()+"x"+win.getSurfaceHeight()+", sDPI "+sDPI[0]+" x "+sDPI[1]+ + ", scale[min "+minSurfacePixelScale[0]+"x"+minSurfacePixelScale[1]+", max "+ + maxSurfacePixelScale[0]+"x"+maxSurfacePixelScale[1]+", req "+ + reqSurfacePixelScale[0]+"x"+reqSurfacePixelScale[1]+" -> has "+ + hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+"]"); + } + + public static PointerIcon[] createPointerIcons(final Display disp) { + final List<PointerIcon> pointerIcons = new ArrayList<PointerIcon>(); + { + disp.createNative(); + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/cross-grey-alpha-16x16.png" }, disp.getClass().getClassLoader(), null); + try { + _pointerIcon = disp.createPointerIcon(res, 8, 8); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); + } catch (final Exception e) { + System.err.println(e.getMessage()); + } + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "newt/data/pointer-grey-alpha-16x24.png" }, disp.getClass().getClassLoader(), null); + try { + _pointerIcon = disp.createPointerIcon(res, 0, 0); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); + } catch (final Exception e) { + System.err.println(e.getMessage()); + } + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-red-alpha-64x64.png" }, disp.getClass().getClassLoader(), null); + try { + _pointerIcon = disp.createPointerIcon(res, 0, 0); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); + } catch (final Exception e) { + System.err.println(e.getMessage()); + } + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "arrow-blue-alpha-64x64.png" }, disp.getClass().getClassLoader(), null); + try { + _pointerIcon = disp.createPointerIcon(res, 0, 0); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); + } catch (final Exception e) { + System.err.println(e.getMessage()); + } + } + if( PNGIcon.isAvailable() ) { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(new String[] { "jogamp-pointer-64x64.png" }, disp.getClass().getClassLoader(), null); + try { + final URLConnection urlConn = res.resolve(0); + if( null != urlConn ) { + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size()+1, image.toString()); + _pointerIcon = disp.createPointerIcon(image, 32, 0); + pointerIcons.add(_pointerIcon); + System.err.printf("Create PointerIcon #%02d: %s%n", pointerIcons.size(), _pointerIcon.toString()); + } + } catch (final Exception e) { + System.err.println(e.getMessage()); + } + } + } + return pointerIcons.toArray(new PointerIcon[pointerIcons.size()]); + } +}
\ No newline at end of file diff --git a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java index 186ffb162..bd5c43d6c 100644 --- a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java +++ b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java @@ -38,6 +38,7 @@ 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.util.Insets; @@ -52,6 +53,7 @@ import jogamp.newt.Debug; import jogamp.newt.swt.SWTEDTUtil; import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; @@ -70,13 +72,14 @@ 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 volatile Rectangle clientArea; + private WindowClosingMode newtChildClosingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private final WindowClosingMode closingMode = WindowClosingMode.DISPOSE_ON_CLOSE; + private volatile Rectangle clientAreaPixels, clientAreaWindow; private volatile SWTNativeWindow nativeWindow; private volatile Window newtChild = null; @@ -126,7 +129,8 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { SWTAccessor.setRealized(this, true); - clientArea = getClientArea(); + clientAreaPixels = SWTAccessor.getClientAreaInPixels(this); + clientAreaWindow = getClientArea(); final AbstractGraphicsDevice device = SWTAccessor.getDevice(this); screen = SWTAccessor.getScreen(device, -1 /* default */); @@ -136,6 +140,10 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { setNEWTChild(child); } + // Bug 1362 fix or workaround: Seems SWT/GTK3 at least performs lazy initialization + // Minimal action required: setBackground of the parent canvas before reparenting! + setBackground(new Color(parent.getDisplay(), 255, 255, 255)); + final Listener listener = new Listener () { @Override public void handleEvent (final Event event) { @@ -147,14 +155,14 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { if( null != nativeWindow || validateNative() ) { if( newtChildReady ) { if( postSetSize ) { - newtChild.setSize(clientArea.width, clientArea.height); + newtChild.setSize(clientAreaPixels.width, clientAreaPixels.height); postSetSize = false; } if( postSetPos ) { - newtChild.setPosition(clientArea.x, clientArea.y); + newtChild.setPosition(clientAreaPixels.x, clientAreaPixels.y); postSetPos = false; } - newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height); + newtChild.windowRepaint(0, 0, clientAreaPixels.width, clientAreaPixels.height); } } break; @@ -168,7 +176,7 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { if( DEBUG ) { System.err.println("NewtCanvasSWT.Event.RESIZE, "+event); } - updateSizeCheck(); + updatePosSizeCheck(false); break; case SWT.Dispose: if( DEBUG ) { @@ -197,14 +205,14 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { } if( SWTAccessor.isOSX ) { // Force newtChild to update its size and position (OSX only) - updatePosSizeCheck(x, y, width, height, true /* updatePos */); + updatePosSizeCheck(true /* updatePos */); } } /** assumes nativeWindow == null ! */ protected final boolean validateNative() { - updateSizeCheck(); - final Rectangle nClientArea = clientArea; + updatePosSizeCheck(false); + final Rectangle nClientArea = clientAreaPixels; if(0 >= nClientArea.width || 0 >= nClientArea.height) { return false; } @@ -242,46 +250,34 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { return null != nativeWindow; } - protected final void updateSizeCheck() { - final Rectangle nClientArea = getClientArea(); - if( null != nClientArea ) { - updatePosSizeCheck(nClientArea.x, nClientArea.y, nClientArea.width, nClientArea.height, false /* updatePos */); - } - } - protected final void updatePosSizeCheck() { - final Rectangle nClientArea = getClientArea(); - if( null != nClientArea ) { - updatePosSizeCheck(nClientArea.x, nClientArea.y, nClientArea.width, nClientArea.height, true /* updatePos */); - } - } - protected final void updatePosSizeCheck(final int newX, final int newY, final int newWidth, final int newHeight, final boolean updatePos) { + protected final void updatePosSizeCheck(final boolean updatePos) { final boolean sizeChanged, posChanged; - final Rectangle nClientArea; + Rectangle nClientAreaPixels = SWTAccessor.getClientAreaInPixels(this); { - final Rectangle oClientArea = clientArea; - sizeChanged = newWidth != oClientArea.width || newHeight != oClientArea.height; - posChanged = newX != oClientArea.x || newY != oClientArea.y; + final Rectangle oClientAreaPixels = clientAreaPixels; + sizeChanged = nClientAreaPixels.width != oClientAreaPixels.width || nClientAreaPixels.height != oClientAreaPixels.height; + posChanged = nClientAreaPixels.x != oClientAreaPixels.x || nClientAreaPixels.y != oClientAreaPixels.y; if( sizeChanged || posChanged ) { - nClientArea = new Rectangle(updatePos ? newX : oClientArea.x, updatePos ? newY : oClientArea.y, newWidth, newHeight); - clientArea = nClientArea; + clientAreaPixels = nClientAreaPixels; + clientAreaWindow = getClientArea(); } else { - nClientArea = clientArea; + nClientAreaPixels = clientAreaPixels; } } if(DEBUG) { final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; - System.err.println("NewtCanvasSWT.updatePosSizeCheck: sizeChanged "+sizeChanged+", posChanged "+posChanged+", updatePos "+updatePos+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(nsh)); + System.err.println("NewtCanvasSWT.updatePosSizeCheck: sizeChanged "+sizeChanged+", posChanged "+posChanged+", updatePos "+updatePos+", ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+nClientAreaPixels.x+"/"+nClientAreaPixels.y+" "+nClientAreaPixels.width+"x"+nClientAreaPixels.height+" - surfaceHandle 0x"+Long.toHexString(nsh)); } if( sizeChanged ) { if( newtChildReady ) { - newtChild.setSize(nClientArea.width, nClientArea.height); + newtChild.setSize(nClientAreaPixels.width, nClientAreaPixels.height); } else { postSetSize = true; } } if( updatePos && posChanged ) { if( newtChildReady ) { - newtChild.setPosition(nClientArea.x, nClientArea.y); + newtChild.setPosition(nClientAreaPixels.x, nClientAreaPixels.y); } else { postSetPos = true; } @@ -330,17 +326,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 +408,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); } } } @@ -419,9 +426,9 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { newtChild.setFocusAction(null); // no AWT focus traversal .. if(add) { - updateSizeCheck(); - final int w = clientArea.width; - final int h = clientArea.height; + updatePosSizeCheck(false); + final int w = clientAreaPixels.width; + final int h = clientAreaPixels.height; // set SWT EDT and start it { @@ -539,12 +546,12 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { @Override public int getSurfaceWidth() { - return clientArea.width; + return clientAreaPixels.width; } @Override public int getSurfaceHeight() { - return clientArea.height; + return clientAreaPixels.height; } @Override diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java index 8bf4bc20f..05df63794 100644 --- a/src/newt/classes/com/jogamp/newt/util/MainThread.java +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -45,6 +45,7 @@ import java.util.List; import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; @@ -171,15 +172,14 @@ public class MainThread { return res; } - static class UserApp extends Thread { + static class UserApp extends InterruptSource.Thread { private final String mainClassNameShort; private final String mainClassName; private final String[] mainClassArgs; private final Method mainClassMain; - private List<Thread> nonDaemonThreadsAtStart; + private List<java.lang.Thread> nonDaemonThreadsAtStart; public UserApp(final String mainClassName, final String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException { - super(); this.mainClassName=mainClassName; this.mainClassArgs=mainClassArgs; @@ -200,10 +200,10 @@ public class MainThread { @Override public void run() { nonDaemonThreadsAtStart = getNonDaemonThreads(); - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart); // start user app .. try { - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" invoke "+mainClassName); mainClassMain.invoke(null, new Object[] { mainClassArgs } ); } catch (final InvocationTargetException ite) { ite.getTargetException().printStackTrace(); @@ -219,30 +219,30 @@ public class MainThread { while( 0 < ( ndtr = getNonDaemonThreadCount(nonDaemonThreadsAtStart) ) ) { if(DEBUG) System.err.println("MainAction.run(): post user app, non daemon threads alive: "+ndtr); try { - Thread.sleep(1000); + java.lang.Thread.sleep(1000); } catch (final InterruptedException e) { e.printStackTrace(); } } - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin: "+ndtr); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" user app fin: "+ndtr); } if ( useMainThread ) { if(isMacOSX) { try { if(DEBUG) { - System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0"); + System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.0"); } ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication", null, null, MainThread.class.getClassLoader()); if(DEBUG) { - System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X"); + System.err.println("MainAction.main(): "+java.lang.Thread.currentThread()+" MainAction fin - stopNSApp.X"); } } catch (final Exception e) { e.printStackTrace(); } } else { - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)"); + if(DEBUG) System.err.println("MainAction.run(): "+java.lang.Thread.currentThread().getName()+" MainAction fin - System.exit(0)"); System.exit(0); } } diff --git a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java index cc159e6ed..c30576ff4 100644 --- a/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/util/applet/JOGLNewtAppletBase.java @@ -42,10 +42,8 @@ import com.jogamp.opengl.GLPipelineFactory; import jogamp.newt.Debug; -import com.jogamp.common.util.IOUtil; -import com.jogamp.newt.Display; +import com.jogamp.common.util.InterruptSource; import com.jogamp.newt.Window; -import com.jogamp.newt.Display.PointerIcon; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.MouseListener; @@ -53,13 +51,18 @@ import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.NEWTDemoListener; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.AnimatorBase; -/** Shows how to deploy an applet using JOGL. This demo must be - referenced from a web page via an <applet> tag. */ - +/** + * Shows how to deploy an applet using JOGL. + * This demo must be referenced from a web page via an <applet> tag. + * <p> + * The demo code uses {@link NEWTDemoListener} functionality. + * </p> + */ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { public static final boolean DEBUG = Debug.debug("Applet"); @@ -69,7 +72,6 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { boolean glClosable; boolean glDebug; boolean glTrace; - PointerIcon pointerIconTest = null; GLEventListener glEventListener = null; GLWindow glWindow = null; @@ -193,8 +195,13 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.addKeyListener((KeyListener)glEventListener); } + glWindow.addWindowListener(reparentHomeListener); + if(!noDefaultKeyListener) { glWindow.addKeyListener(this); + final NEWTDemoListener newtDemoListener = new NEWTDemoListener(glWindow); + glWindow.addKeyListener(newtDemoListener); + glWindow.addMouseListener(newtDemoListener); } glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err); @@ -220,7 +227,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { null == glWindow.getParent() && null != parentWin && 0 != parentWin.getWindowHandle() ) { // we may be called directly by the native EDT - new Thread(new Runnable() { + new InterruptSource.Thread(null, new Runnable() { @Override public void run() { if( glWindow.isNativeValid() && null != parentWin && 0 != parentWin.getWindowHandle() ) { @@ -235,24 +242,13 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { if(isValid) { glWindow.setVisible(true); glWindow.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); - if( null == pointerIconTest ) { - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } ); - final Display disp = glWindow.getScreen().getDisplay(); - try { - pointerIconTest = disp.createPointerIcon(res, 8, 8); - } catch (final Exception e) { - e.printStackTrace(); - } - } glAnimator.start(); parentWin = glWindow.getParent(); - glWindow.addWindowListener(reparentHomeListener); } } public void stop() { if(null!=glAnimator) { - glWindow.removeWindowListener(reparentHomeListener); glAnimator.stop(); glWindow.setVisible(false); } @@ -291,10 +287,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { _gl = _gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, _gl, new Object[] { System.err } ) ); } catch (final Exception e) {e.printStackTrace();} } - - if(glSwapInterval>=0) { - _gl.setSwapInterval(glSwapInterval); - } + _gl.setSwapInterval(glSwapInterval); } @Override public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { @@ -315,27 +308,14 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { if( !e.isPrintableKey() || e.isAutoRepeat() ) { return; } - if(e.getKeyChar()=='d') { - new Thread() { - public void run() { - glWindow.setUndecorated(!glWindow.isUndecorated()); - } }.start(); - } if(e.getKeyChar()=='f') { - new Thread() { - public void run() { - glWindow.setFullscreen(!glWindow.isFullscreen()); - } }.start(); - } else if(e.getKeyChar()=='a') { - new Thread() { - public void run() { - glWindow.setAlwaysOnTop(!glWindow.isAlwaysOnTop()); - } }.start(); - } else if(e.getKeyChar()=='r' && null!=parentWin) { - new Thread() { + + if(e.getKeyChar()=='r' && 0==e.getModifiers() && null!=parentWin) { + e.setConsumed(true); + glWindow.invokeOnNewThread(null, false, new Runnable() { public void run() { if(null == glWindow.getParent()) { - glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */); - } else { + glWindow.reparentWindow(parentWin, -1, -1, 0 /* hints */); + } else { final InsetsImmutable insets = glWindow.getInsets(); final int x, y; if ( 0 >= insets.getTopHeight() ) { @@ -349,43 +329,13 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.reparentWindow(null, x, y, 0 /* hints */); glWindow.setDefaultCloseOperation( glClosable ? WindowClosingMode.DISPOSE_ON_CLOSE : WindowClosingMode.DO_NOTHING_ON_CLOSE ); } - } }.start(); - } else if(e.getKeyChar()=='c') { - new Thread() { - public void run() { - System.err.println("[set pointer-icon pre]"); - final PointerIcon currentPI = glWindow.getPointerIcon(); - glWindow.setPointerIcon( currentPI == pointerIconTest ? null : pointerIconTest); - System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon()); - } }.start(); - } else if(e.getKeyChar()=='i') { - new Thread() { - public void run() { - System.err.println("[set mouse visible pre]: "+glWindow.isPointerVisible()); - glWindow.setPointerVisible(!glWindow.isPointerVisible()); - System.err.println("[set mouse visible post]: "+glWindow.isPointerVisible()); - } }.start(); - } else if(e.getKeyChar()=='j') { - new Thread() { - public void run() { - final Thread t = glWindow.setExclusiveContextThread(null); - System.err.println("[set mouse confined pre]: "+glWindow.isPointerConfined()); - glWindow.confinePointer(!glWindow.isPointerConfined()); - System.err.println("[set mouse confined post]: "+glWindow.isPointerConfined()); - glWindow.setExclusiveContextThread(t); - } }.start(); - } else if(e.getKeyChar()=='w') { - new Thread() { - public void run() { - System.err.println("[set mouse pos pre]"); - glWindow.warpPointer(glWindow.getSurfaceWidth()/2, glWindow.getSurfaceHeight()/2); - System.err.println("[set mouse pos post]"); - } }.start(); + } } ); } } @Override public void keyReleased(final KeyEvent e) { } + } diff --git a/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java b/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java index 9b9b7d532..fce43d71f 100644 --- a/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java +++ b/src/newt/classes/com/jogamp/newt/util/applet3/JOGLNewtApplet3Run.java @@ -243,7 +243,7 @@ public class JOGLNewtApplet3Run implements Applet3 { } this.ctx = ctx; String glEventListenerClazzName=null; - int glSwapInterval=0; + int glSwapInterval=1; boolean glDebug=false; boolean glTrace=false; boolean glNoDefaultKeyListener = false; |