summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-07-27 20:00:06 +0200
committerSven Gothel <[email protected]>2015-07-27 20:00:06 +0200
commit6ae08be1742e6d805b316c0d440364854a49e68f (patch)
tree666866771aeb8fe880fd810f5a664e8e0315a6e9
parent8e1f5fc43ba84d5e6373f0c29089ac32b7ce95dd (diff)
Bug 1184 - JOGL AWT Canvas Components don't update AWTGraphicsConfiguration when reconfigured.
JOGL AWT Components, e.g. GLCanvas or NewtCanvasAWT, may be reconfigured by moving them to another display/monitor or by other means. Since AWT has no means to notify the user code via an event, JOGL components usually determine the reconfiguration via the override 'GraphicsConfiguration getGraphicsConfiguration()'. GLCanvas is sensible to this reconfiguration, however its AWTGraphicsConfiguration (owned via JAWTWindow) is not changed. Implement reconfiguration detection for all JOGL AWT Components and update the AWTGraphicsConfiguration if required. For now, constraint reconfiguration on GraphicsDevice change as currently implemented in GLCanvas. The updated AWTGraphicsConfiguration allows using the updated GraphicsDevice as it might be required for further information, e.g. pixel-scale on OSX.
-rw-r--r--make/scripts/tests.sh5
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java269
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java38
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java40
-rw-r--r--src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java137
-rw-r--r--src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java50
6 files changed, 378 insertions, 161 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 202b7ce38..88d3626cf 100644
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -137,7 +137,7 @@ function jrun() {
#D_ARGS="-Djogl.debug.GLSLCode -Djogl.debug.TraceGL"
#D_ARGS="-Djogl.debug.GLSLCode -Djogl.debug.DebugGL"
#D_ARGS="-Djogl.debug.GLContext -Dnativewindow.debug.JAWT -Dnewt.debug.Window"
- #D_ARGS="-Dnativewindow.debug.JAWT -Djogl.debug.GLCanvas"
+ D_ARGS="-Dnativewindow.debug.JAWT -Djogl.debug.GLCanvas"
#D_ARGS="-Dnativewindow.debug.JAWT -Djogamp.debug.TaskBase.TraceSource"
#D_ARGS="-Dnativewindow.debug.JAWT"
#D_ARGS="-Djogl.debug.GLContext.TraceSwitch"
@@ -423,6 +423,7 @@ function testawtswt() {
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $*
+testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestRulerNEWT01 $*
#testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $*
#testawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtCanvasAWTDemo $*
@@ -512,7 +513,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLException01NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestMapBufferRead01NEWT $*
-testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestMapBufferRead02NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestMapBufferRead02NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestRedSquareES2NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $*
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
index 11d217535..5f59f7e6d 100644
--- a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
@@ -173,7 +173,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final RecursiveLock lock = LockFactory.createRecursiveLock();
private final GLDrawableHelper helper = new GLDrawableHelper();
- private AWTGraphicsConfiguration awtConfig;
private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
private volatile GLContextImpl context; // volatile: avoid locking for read-only access
@@ -187,9 +186,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private final GLCapabilitiesImmutable capsReqUser;
private final GLCapabilitiesChooser chooser;
private int additionalCtxCreationFlags = 0;
- private final GraphicsDevice device;
private boolean shallUseOffscreenLayer = false;
+ private volatile GraphicsDevice awtDeviceReq; // one time user req.
+ private volatile AWTGraphicsConfiguration awtConfig;
private volatile boolean isShowing;
private final HierarchyListener hierarchyListener = new HierarchyListener() {
@Override
@@ -270,16 +270,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
setShallUseOffscreenLayer(true); // trigger offscreen layer - if supported
}
- if(null==device) {
- final GraphicsConfiguration gc = super.getGraphicsConfiguration();
- if(null!=gc) {
- this.device = gc.getDevice();
- } else {
- this.device = null;
- }
- } else {
- this.device = device;
- }
+ // One time user AWT GraphicsDevice request
+ awtDeviceReq = device;
// instantiation will be issued in addNotify()
this.chooser = chooser;
@@ -330,124 +322,111 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
/**
- * Overridden to choose a GraphicsConfiguration on a parent container's
- * GraphicsDevice because both devices
+ * {@inheritDoc}
+ * <p>
+ * Overridden to choose a {@link GraphicsConfiguration} from a parent container's
+ * {@link GraphicsDevice}.
+ * </p>
+ * <p>
+ * Method also intercepts {@link GraphicsConfiguration} changes regarding to
+ * its capabilities and its {@link GraphicsDevice}. This may happen in case
+ * the display changes its configuration or the component is moved to another screen.
+ * </p>
*/
@Override
public GraphicsConfiguration getGraphicsConfiguration() {
- /*
- * Workaround for problems with Xinerama and java.awt.Component.checkGD
- * when adding to a container on a different graphics device than the
- * one that this Canvas is associated with.
- *
- * GC will be null unless:
- * - A native peer has assigned it. This means we have a native
- * peer, and are already comitted to a graphics configuration.
- * - This canvas has been added to a component hierarchy and has
- * an ancestor with a non-null GC, but the native peer has not
- * yet been created. This means we can still choose the GC on
- * all platforms since the peer hasn't been created.
- */
- final GraphicsConfiguration gc = super.getGraphicsConfiguration();
-
- if( Beans.isDesignTime() ) {
- return gc;
- }
-
- /*
- * chosen is only non-null on platforms where the GLDrawableFactory
- * returns a non-null GraphicsConfiguration (in the GLCanvas
- * constructor).
- *
- * if gc is from this Canvas' native peer then it should equal chosen,
- * otherwise it is from an ancestor component that this Canvas is being
- * added to, and we go into this block.
- */
- GraphicsConfiguration chosen = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null;
-
- if (gc != null && chosen != null && !chosen.equals(gc)) {
- /*
- * Check for compatibility with gc. If they differ by only the
- * device then return a new GCconfig with the super-class' GDevice
- * (and presumably the same visual ID in Xinerama).
- *
+ /**
+ * parentGC will be null unless:
+ * - A native peer has assigned it. This means we have a native
+ * peer, and are already committed to a graphics configuration.
+ * - This canvas has been added to a component hierarchy and has
+ * an ancestor with a non-null GC, but the native peer has not
+ * yet been created. This means we can still choose the GC on
+ * all platforms since the peer hasn't been created.
*/
- if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
- /*
- * Here we select a GraphicsConfiguration on the alternate
- * device that is presumably identical to the chosen
- * configuration, but on the other device.
- *
- * Should really check to ensure that we select a configuration
- * with the same X visual ID for Xinerama screens, otherwise the
- * GLDrawable may have the wrong visual ID (I don't think this
- * ever gets updated). May need to add a method to
- * X11GLDrawableFactory to do this in a platform specific
- * manner.
- *
- * However, on platforms where we can actually get into this
- * block, both devices should have the same visual list, and the
- * same configuration should be selected here.
- */
- final AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(),
- (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(),
- chooser, gc.getDevice());
- final GraphicsConfiguration compatible = config.getAWTGraphicsConfiguration();
- final boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
- if(DEBUG) {
- System.err.println(getThreadName()+": Info:");
- System.err.println("Created Config (n): HAVE GC "+chosen);
- System.err.println("Created Config (n): THIS GC "+gc);
- System.err.println("Created Config (n): Choosen GC "+compatible);
- System.err.println("Created Config (n): HAVE CF "+awtConfig);
- System.err.println("Created Config (n): Choosen CF "+config);
- System.err.println("Created Config (n): EQUALS CAPS "+equalCaps);
- // Thread.dumpStack();
- }
+ final GraphicsConfiguration parentGC = super.getGraphicsConfiguration();
- if (compatible != null) {
- /*
- * Save the new GC for equals test above, and to return to
- * any outside callers of this method.
- */
- chosen = compatible;
-
- if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) {
- // complete destruction!
- destroyImpl( true );
- // recreation!
- awtConfig = config;
- createJAWTDrawableAndContext();
- validateGLDrawable();
- } else {
- awtConfig = config;
+ if( Beans.isDesignTime() ) {
+ return parentGC;
+ }
+ final GraphicsConfiguration oldGC = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null;
+
+ if ( null != parentGC && null != oldGC && !oldGC.equals(parentGC) ) {
+ // Previous oldGC != parentGC of native peer
+
+ if ( !oldGC.getDevice().getIDstring().equals(parentGC.getDevice().getIDstring()) ) {
+ // Previous oldGC's GraphicsDevice != parentGC's GraphicsDevice of native peer
+
+ /**
+ * Here we select a GraphicsConfiguration on the alternate device.
+ * In case the new configuration differs (-> !equalCaps),
+ * we might need a reconfiguration,
+ */
+ final AWTGraphicsConfiguration newConfig = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(),
+ (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(),
+ chooser, parentGC.getDevice());
+ final GraphicsConfiguration newGC = newConfig.getAWTGraphicsConfiguration();
+ final boolean equalCaps = newConfig.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
+ if(DEBUG) {
+ System.err.println(getThreadName()+": getGraphicsConfiguration() Info: Changed GC and GD");
+ System.err.println("Created Config (n): Old GC "+oldGC);
+ System.err.println("Created Config (n): Old GD "+oldGC.getDevice().getIDstring());
+ System.err.println("Created Config (n): Parent GC "+parentGC);
+ System.err.println("Created Config (n): Parent GD "+parentGC.getDevice().getIDstring());
+ System.err.println("Created Config (n): New GC "+newGC);
+ System.err.println("Created Config (n): New GD "+newGC.getDevice().getIDstring());
+ System.err.println("Created Config (n): Old CF "+awtConfig);
+ System.err.println("Created Config (n): New CF "+newConfig);
+ System.err.println("Created Config (n): EQUALS CAPS "+equalCaps);
+ // Thread.dumpStack();
+ }
+ if ( null != newGC ) {
+ if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) {
+ // complete destruction!
+ destroyImpl( true );
+ // recreation!
+ setAWTGraphicsConfiguration(newConfig);
+ createJAWTDrawableAndContext();
+ validateGLDrawable();
+ } else {
+ setAWTGraphicsConfiguration(newConfig);
+ }
+ /**
+ * Return the newGC, which covers the desired capabilities and is compatible
+ * with the available GC's of its devices.
+ */
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: getGraphicsConfiguration - end.01: newGC "+newGC);
+ }
+ return newGC;
+ } else {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: getGraphicsConfiguration - end.00: oldGC "+oldGC);
+ }
+ }
}
- }
+ /**
+ * If a new GC was _not_ found/defined above,
+ * method returns oldGC as selected in the constructor or first addNotify().
+ * This may cause an exception in Component.checkGD when adding to a
+ * container, and is the desired behavior.
+ */
+ return oldGC;
+ } else if (null == parentGC) {
+ /**
+ * The parentGC is null, which means we have no native peer, and are not
+ * part of a (realized) component hierarchy. So we return the
+ * desired visual that was selected in the constructor (possibly
+ * null).
+ */
+ return oldGC;
+ } else {
+ /**
+ * Otherwise we have not explicitly selected a GC in the constructor, so
+ * just return what Canvas would have.
+ */
+ return parentGC;
}
-
- /*
- * If a compatible GC was not found in the block above, this will
- * return the GC that was selected in the constructor (and might
- * cause an exception in Component.checkGD when adding to a
- * container, but in this case that would be the desired behavior).
- *
- */
- return chosen;
- } else if (gc == null) {
- /*
- * The GC is null, which means we have no native peer, and are not
- * part of a (realized) component hierarchy. So we return the
- * desired visual that was selected in the constructor (possibly
- * null).
- */
- return chosen;
- }
-
- /*
- * Otherwise we have not explicitly selected a GC in the constructor, so
- * just return what Canvas would have.
- */
- return gc;
}
@Override
@@ -606,20 +585,35 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
} else {
/**
* 'super.addNotify()' determines the GraphicsConfiguration,
- * while calling this class's overriden 'getGraphicsConfiguration()' method
+ * while calling this class's overridden 'getGraphicsConfiguration()' method
* after which it creates the native peer.
* Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
* is being used in getGraphicsConfiguration().
* This code order also allows recreation, ie re-adding the GLCanvas.
*/
- awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
- if(null==awtConfig) {
- throw new GLException("Error: NULL AWTGraphicsConfiguration");
- }
// before native peer is valid: X11
disableBackgroundErase();
+ final GraphicsDevice awtDevice;
+ if(null==awtDeviceReq) {
+ // Query AWT GraphicsDevice from parent tree, default
+ final GraphicsConfiguration gc = super.getGraphicsConfiguration();
+ if(null==gc) {
+ throw new GLException("Error: NULL AWT GraphicsConfiguration");
+ }
+ awtDevice = gc.getDevice();
+ } else {
+ // Use one time user AWT GraphicsDevice request
+ awtDevice = awtDeviceReq;
+ awtDeviceReq = null;
+ }
+ final AWTGraphicsConfiguration awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, awtDevice);
+ if(null==awtConfig) {
+ throw new GLException("Error: NULL AWTGraphicsConfiguration");
+ }
+ setAWTGraphicsConfiguration(awtConfig);
+
// issues getGraphicsConfiguration() and creates the native peer
super.addNotify();
@@ -775,6 +769,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
return false;
}
+ private void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config) {
+ // Cache awtConfig
+ awtConfig = config;
+ if( null != jawtWindow ) {
+ // Notify JAWTWindow ..
+ jawtWindow.setAWTGraphicsConfiguration(config);
+ }
+ }
+
/** <p>Overridden to track when this component is removed from a
container. Subclasses which override this method must call
super.removeNotify() in their removeNotify() method in order to
@@ -1394,7 +1397,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post GraphicsDevice: "+adeviceMsg+", result: "+closed);
}
}
- awtConfig=null;
+ awtConfig = null;
}
};
@@ -1546,10 +1549,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
if( Beans.isDesignTime() ) {
return null;
}
-
- final AbstractGraphicsScreen aScreen = null != device ?
- AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT):
- AWTGraphicsScreen.createDefault();
+ if( null == device ) {
+ throw new GLException("Error: NULL AWT GraphicsDevice");
+ }
+ final AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT);
AWTGraphicsConfiguration config = null;
if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java
index 62fd49092..cc70b6b7b 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java
@@ -73,19 +73,42 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple
}
/**
+ * @deprecated Use {@link #create(GraphicsConfiguration, CapabilitiesImmutable, CapabilitiesImmutable)}
+ * Method constructs a new {@link AWTGraphicsConfiguration} primarily based
+ * on the given {@link Component}'s {@link GraphicsConfiguration}.
+ * @param awtComp the {@link Component}, which {@link GraphicsConfiguration} is used for the resulting {@link AWTGraphicsConfiguration}
* @param capsChosen if null, <code>capsRequested</code> is copied and aligned
* with the graphics {@link Capabilities} of the AWT Component to produce the chosen {@link Capabilities}.
* Otherwise the <code>capsChosen</code> is used.
* @param capsRequested if null, default {@link Capabilities} are used, otherwise the given values.
*/
- public static AWTGraphicsConfiguration create(final Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) {
- final GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration();
- if(null==awtGfxConfig) {
- throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp);
+ public static AWTGraphicsConfiguration create(final Component awtComp, final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested) {
+ if(null==awtComp) {
+ throw new IllegalArgumentException("Null AWT Component");
}
- final GraphicsDevice awtGraphicsDevice = awtGfxConfig.getDevice();
+ final GraphicsConfiguration gc = awtComp.getGraphicsConfiguration();
+ if( null == gc ) {
+ throw new NativeWindowException("Null AWT GraphicsConfiguration @ "+awtComp);
+ }
+ return create(gc, capsChosen, capsRequested);
+ }
+
+ /**
+ * Method constructs a new {@link AWTGraphicsConfiguration} primarily based
+ * on the given {@link GraphicsConfiguration}.
+ * @param gc the {@link GraphicsConfiguration} for the resulting {@link AWTGraphicsConfiguration}
+ * @param capsChosen if null, <code>capsRequested</code> is copied and aligned
+ * with the graphics {@link Capabilities} of the AWT Component to produce the chosen {@link Capabilities}.
+ * Otherwise the <code>capsChosen</code> is used.
+ * @param capsRequested if null, default {@link Capabilities} are used, otherwise the given values.
+ */
+ public static AWTGraphicsConfiguration create(final GraphicsConfiguration gc, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) {
+ if(null==gc) {
+ throw new IllegalArgumentException("Null AWT GraphicsConfiguration");
+ }
+ final GraphicsDevice awtGraphicsDevice = gc.getDevice();
if(null==awtGraphicsDevice) {
- throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsDevice @ "+awtGfxConfig);
+ throw new NativeWindowException("Null AWT GraphicsDevice @ "+gc);
}
// Create Device/Screen
@@ -96,7 +119,6 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple
capsRequested = new Capabilities();
}
if(null==capsChosen) {
- final GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration();
capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsRequested, gc);
}
final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice, capsChosen);
@@ -105,7 +127,7 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple
return (AWTGraphicsConfiguration) config;
}
// System.err.println("Info: AWTGraphicsConfiguration.create: Expected AWTGraphicsConfiguration got: "+config.getClass()+" w/ factory "+factory.getClass()+" - Unable to encapsulate native GraphicsConfiguration.");
- return new AWTGraphicsConfiguration(awtScreen, capsChosen, capsRequested, awtGfxConfig);
+ return new AWTGraphicsConfiguration(awtScreen, capsChosen, capsRequested, gc);
}
// open access to superclass method
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
index d315e1876..3a8cbefc6 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java
@@ -49,7 +49,6 @@ import java.awt.Container;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.GraphicsConfiguration;
-import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
@@ -91,10 +90,10 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
// lifetime: forever
protected final Component component;
private final AppContextInfo appContextInfo;
- private final AWTGraphicsConfiguration config; // control access due to delegation
private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock();
private final JAWTComponentListener jawtComponentListener;
+ private volatile AWTGraphicsConfiguration awtConfig; // control access through delegation
// lifetime: valid after lock but may change with each 1st lock, purges after invalidate
private boolean isApplet;
@@ -128,9 +127,9 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
appContextInfo = new AppContextInfo("<init>");
this.component = (Component)comp;
- this.config = (AWTGraphicsConfiguration) config;
this.jawtComponentListener = new JAWTComponentListener();
invalidate();
+ this.awtConfig = (AWTGraphicsConfiguration) config;
this.isApplet = false;
this.offscreenSurfaceLayer = 0;
}
@@ -265,6 +264,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
invalidateNative();
jawt = null;
+ awtConfig = null;
isOffscreenLayerSurface = false;
drawable= 0;
drawable_old = 0;
@@ -280,6 +280,34 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
}
protected abstract void invalidateNative();
+ /**
+ * Set a new {@link AWTGraphicsConfiguration} instance,
+ * as required if {@link #getAWTComponent() upstream component}'s {@link GraphicsConfiguration} has been changed
+ * due to reconfiguration, e.g. moving to a different monitor or changed capabilities.
+ * <p>
+ * {@link #getAWTComponent() Upstream component} shall override {@link Component#getGraphicsConfiguration()},
+ * which shall call this method if detecting a reconfiguration.
+ * See JOGL's GLCanvas and NewtCanvasAWT.
+ * </p>
+ * @param config the new {@link AWTGraphicsConfiguration}
+ * @see #getAWTGraphicsConfiguration()
+ */
+ public final void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config) {
+ if(DEBUG) {
+ System.err.println(jawtStr()+".setAWTGraphicsConfiguration(): "+this.awtConfig+" -> "+config);
+ // Thread.dumpStack();
+ }
+ this.awtConfig = config;
+ }
+ /**
+ * Return the current {@link AWTGraphicsConfiguration} instance,
+ * which also holds its {@link #getAWTComponent() upstream component}'s {@link GraphicsConfiguration}
+ * @see #setAWTGraphicsConfiguration(AWTGraphicsConfiguration)
+ */
+ public final AWTGraphicsConfiguration getAWTGraphicsConfiguration() {
+ return awtConfig;
+ }
+
@Override
public boolean setSurfaceScale(final float[] pixelScale) {
System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2);
@@ -527,7 +555,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
@Override
public final void setChosenCapabilities(final CapabilitiesImmutable caps) {
((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps);
- config.setChosenCapabilities(caps);
+ awtConfig.setChosenCapabilities(caps);
}
@Override
@@ -706,7 +734,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
@Override
public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
- return config.getNativeGraphicsConfiguration();
+ return awtConfig.getNativeGraphicsConfiguration();
}
@Override
@@ -877,7 +905,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface,
"], pixels[scale "+getPixelScaleX()+", "+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
", visible "+component.isVisible());
sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+
- ",\n\tconfig "+config+
+ ",\n\tconfig "+awtConfig+
",\n\tawtComponent "+getAWTComponent()+
",\n\tsurfaceLock "+surfaceLock+"]");
diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
index 5920d6de8..0a27f7f22 100644
--- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
+++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
@@ -37,6 +37,7 @@ import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
import java.awt.KeyboardFocusManager;
import java.awt.geom.NoninvertibleTransformException;
import java.beans.Beans;
@@ -47,6 +48,7 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Set;
+import com.jogamp.nativewindow.CapabilitiesImmutable;
import com.jogamp.nativewindow.NativeWindow;
import com.jogamp.nativewindow.OffscreenLayerOption;
import com.jogamp.nativewindow.WindowClosingProtocol;
@@ -71,6 +73,7 @@ import jogamp.opengl.awt.AWTTilePainter;
import com.jogamp.common.ExceptionUtils;
import com.jogamp.common.util.awt.AWTEDTExecutor;
+import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
import com.jogamp.nativewindow.awt.AWTPrintLifecycle;
import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol;
import com.jogamp.nativewindow.awt.JAWTWindow;
@@ -101,7 +104,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
public static final boolean DEBUG = Debug.debug("Window");
private final Object sync = new Object();
- private JAWTWindow jawtWindow = null;
+ private volatile JAWTWindow jawtWindow = null; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
private boolean isApplet = false;
private boolean shallUseOffscreenLayer = false;
private Window newtChild = null;
@@ -112,6 +115,8 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
private final AWTAdapter awtMouseAdapter;
private final AWTAdapter awtKeyAdapter;
+ private volatile AWTGraphicsConfiguration awtConfig;
+
/** Mitigates Bug 910 (IcedTea-Web), i.e. crash via removeNotify() invoked before Applet.destroy(). */
private boolean destroyJAWTPending = false;
/** Mitigates Bug 910 (IcedTea-Web), i.e. crash via removeNotify() invoked before Applet.destroy(). */
@@ -452,14 +457,142 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
}
}
+ private void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config) {
+ // Cache awtConfig
+ awtConfig = config;
+ if( null != jawtWindow ) {
+ // Notify JAWTWindow ..
+ jawtWindow.setAWTGraphicsConfiguration(config);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Overridden to choose a {@link GraphicsConfiguration} from a parent container's
+ * {@link GraphicsDevice}.
+ * </p>
+ * <p>
+ * Method also intercepts {@link GraphicsConfiguration} changes regarding to
+ * its capabilities and its {@link GraphicsDevice}. This may happen in case
+ * the display changes its configuration or the component is moved to another screen.
+ * </p>
+ */
+ @Override
+ public GraphicsConfiguration getGraphicsConfiguration() {
+ /**
+ * parentGC will be null unless:
+ * - A native peer has assigned it. This means we have a native
+ * peer, and are already committed to a graphics configuration.
+ * - This canvas has been added to a component hierarchy and has
+ * an ancestor with a non-null GC, but the native peer has not
+ * yet been created. This means we can still choose the GC on
+ * all platforms since the peer hasn't been created.
+ */
+ final GraphicsConfiguration parentGC = super.getGraphicsConfiguration();
+
+ if( Beans.isDesignTime() ) {
+ return parentGC;
+ }
+ final GraphicsConfiguration oldGC = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null;
+
+ if ( null != parentGC && null != oldGC && !oldGC.equals(parentGC) ) {
+ // Previous oldGC != parentGC of native peer
+
+ if ( !oldGC.getDevice().getIDstring().equals(parentGC.getDevice().getIDstring()) ) {
+ // Previous oldGC's GraphicsDevice != parentGC's GraphicsDevice of native peer
+
+ /**
+ * Here we select a GraphicsConfiguration on the alternate device.
+ * In case the new configuration differs (-> !equalCaps),
+ * we might need a reconfiguration,
+ */
+ final AWTGraphicsConfiguration newConfig = AWTGraphicsConfiguration.create(parentGC,
+ awtConfig.getChosenCapabilities(),
+ awtConfig.getRequestedCapabilities());
+ final GraphicsConfiguration newGC = newConfig.getAWTGraphicsConfiguration();
+ final boolean equalCaps = newConfig.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
+ if(DEBUG) {
+ System.err.println(getThreadName()+": getGraphicsConfiguration() Info: Changed GC and GD");
+ System.err.println("Created Config (n): Old GC "+oldGC);
+ System.err.println("Created Config (n): Old GD "+oldGC.getDevice().getIDstring());
+ System.err.println("Created Config (n): Parent GC "+parentGC);
+ System.err.println("Created Config (n): Parent GD "+parentGC.getDevice().getIDstring());
+ System.err.println("Created Config (n): New GC "+newGC);
+ System.err.println("Created Config (n): Old CF "+awtConfig);
+ System.err.println("Created Config (n): New CF "+newConfig);
+ System.err.println("Created Config (n): EQUALS CAPS "+equalCaps);
+ // Thread.dumpStack();
+ }
+ if ( null != newGC ) {
+ setAWTGraphicsConfiguration(newConfig);
+ /**
+ * Return the newGC, which covers the desired capabilities and is compatible
+ * with the available GC's of its devices.
+ */
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: getGraphicsConfiguration - end.01: newGC "+newGC);
+ }
+ return newGC;
+ } else {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: getGraphicsConfiguration - end.00: oldGC "+oldGC);
+ }
+ }
+ }
+ /**
+ * If a new GC was _not_ found/defined above,
+ * method returns oldGC as selected in the constructor or first addNotify().
+ * This may cause an exception in Component.checkGD when adding to a
+ * container, and is the desired behavior.
+ */
+ return oldGC;
+ } else if (null == parentGC) {
+ /**
+ * The parentGC is null, which means we have no native peer, and are not
+ * part of a (realized) component hierarchy. So we return the
+ * desired visual that was selected in the constructor (possibly
+ * null).
+ */
+ return oldGC;
+ } else {
+ /**
+ * Otherwise we have not explicitly selected a GC in the constructor, so
+ * just return what Canvas would have.
+ */
+ return parentGC;
+ }
+ }
+ private static String getThreadName() { return Thread.currentThread().getName(); }
+
@Override
public void addNotify() {
if( Beans.isDesignTime() ) {
super.addNotify();
} else {
+ /**
+ * 'super.addNotify()' determines the GraphicsConfiguration,
+ * while calling this class's overridden 'getGraphicsConfiguration()' method
+ * after which it creates the native peer.
+ * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
+ * is being used in getGraphicsConfiguration().
+ * This code order also allows recreation, ie re-adding the GLCanvas.
+ */
// before native peer is valid: X11
disableBackgroundErase();
+ // Query AWT GraphicsDevice from parent tree, default
+ final GraphicsConfiguration gc = super.getGraphicsConfiguration();
+ if(null==gc) {
+ throw new GLException("Error: NULL AWT GraphicsConfiguration");
+ }
+ final CapabilitiesImmutable capsReq = null != newtChild ? newtChild.getRequestedCapabilities() : null;
+ final AWTGraphicsConfiguration awtConfig = AWTGraphicsConfiguration.create(gc, null, capsReq);
+ if(null==awtConfig) {
+ throw new GLException("Error: NULL AWTGraphicsConfiguration");
+ }
+ setAWTGraphicsConfiguration(awtConfig);
+
// creates the native peer
super.addNotify();
@@ -472,7 +605,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
System.err.println("NewtCanvasAWT.addNotify.0 - isApplet "+isApplet+", addedOnAWTEDT "+EventQueue.isDispatchThread()+" @ "+currentThreadName());
ExceptionUtils.dumpStack(System.err);
}
- jawtWindow = NewtFactoryAWT.getNativeWindow(NewtCanvasAWT.this, null != newtChild ? newtChild.getRequestedCapabilities() : null);
+ jawtWindow = NewtFactoryAWT.getNativeWindow(NewtCanvasAWT.this, awtConfig);
jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
// enforce initial lock on AWT-EDT, allowing acquisition of pixel-scale
jawtWindow.lockSurface();
diff --git a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java
index 8eaca7c0e..cc71fb559 100644
--- a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java
+++ b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java
@@ -28,8 +28,6 @@
package jogamp.newt.awt;
-import java.awt.GraphicsDevice;
-
import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
import com.jogamp.nativewindow.CapabilitiesImmutable;
import com.jogamp.nativewindow.NativeWindow;
@@ -57,6 +55,8 @@ public class NewtFactoryAWT extends NewtFactory {
public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window");
/**
+ * @deprecated Use {@link #getNativeWindow(java.awt.Component, AWTGraphicsConfiguration)}
+ *
* Wraps an AWT component into a {@link com.jogamp.nativewindow.NativeWindow} utilizing the {@link com.jogamp.nativewindow.NativeWindowFactory},<br>
* using a configuration agnostic dummy {@link com.jogamp.nativewindow.DefaultGraphicsConfiguration}.<br>
* <p>
@@ -78,9 +78,37 @@ public class NewtFactoryAWT extends NewtFactory {
return getNativeWindow( (java.awt.Component) awtCompObject, capsRequested );
}
+ /**
+ * @deprecated Use {@link #getNativeWindow(java.awt.Component, AWTGraphicsConfiguration)}
+ * @param awtComp
+ * @param capsRequested
+ * @return
+ */
public static JAWTWindow getNativeWindow(final java.awt.Component awtComp, final CapabilitiesImmutable capsRequested) {
- final AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, null, capsRequested);
- final NativeWindow nw = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow
+ final AWTGraphicsConfiguration awtConfig = AWTGraphicsConfiguration.create(awtComp, null, capsRequested);
+ return getNativeWindow(awtComp, awtConfig);
+ }
+
+ /**
+ * Wraps an AWT component into a {@link com.jogamp.nativewindow.NativeWindow} utilizing the {@link com.jogamp.nativewindow.NativeWindowFactory},<br>
+ * using the given {@link AWTGraphicsConfiguration}.
+ * <p>
+ * The actual wrapping implementation is {@link com.jogamp.nativewindow.awt.JAWTWindow}.
+ * </p>
+ * <p>
+ * The required {@link AWTGraphicsConfiguration} may be constructed via
+ * {@link AWTGraphicsConfiguration#create(java.awt.GraphicsConfiguration, CapabilitiesImmutable, CapabilitiesImmutable)}
+ * </p>
+ * <p>
+ * Purpose of this wrapping is to access the AWT window handle,<br>
+ * not to actually render into it.
+ * </p>
+ *
+ * @param awtComp {@link java.awt.Component}
+ * @param awtConfig {@link AWTGraphicsConfiguration} reflecting the used {@link java.awt.GraphicsConfiguration}
+ */
+ public static JAWTWindow getNativeWindow(final java.awt.Component awtComp, final AWTGraphicsConfiguration awtConfig) {
+ final NativeWindow nw = NativeWindowFactory.getNativeWindow(awtComp, awtConfig); // a JAWTWindow
if(! ( nw instanceof JAWTWindow ) ) {
throw new NativeWindowException("Not an AWT NativeWindow: "+nw);
}
@@ -101,13 +129,15 @@ public class NewtFactoryAWT extends NewtFactory {
* @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable}
* or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}.
*/
- private static void checkComponentValid(final java.awt.Component awtComp) throws IllegalArgumentException {
+ private static java.awt.GraphicsConfiguration checkComponentValid(final java.awt.Component awtComp) throws IllegalArgumentException {
if( !awtComp.isDisplayable() ) {
throw new IllegalArgumentException("Given AWT-Component is not displayable: "+awtComp);
}
- if( null == awtComp.getGraphicsConfiguration() ) {
+ final java.awt.GraphicsConfiguration gc = awtComp.getGraphicsConfiguration();
+ if( null == gc ) {
throw new IllegalArgumentException("Given AWT-Component has no GraphicsConfiguration set: "+awtComp);
}
+ return gc;
}
/**
@@ -120,8 +150,8 @@ public class NewtFactoryAWT extends NewtFactory {
* @see #getAbstractGraphicsScreen(java.awt.Component)
*/
public static Display createDisplay(final java.awt.Component awtComp, final boolean reuse) throws IllegalArgumentException {
- checkComponentValid(awtComp);
- final GraphicsDevice device = awtComp.getGraphicsConfiguration().getDevice();
+ final java.awt.GraphicsConfiguration gc = checkComponentValid(awtComp);
+ final java.awt.GraphicsDevice device = gc.getDevice();
final String displayConnection;
final String nwt = NativeWindowFactory.getNativeWindowType(true);
@@ -174,13 +204,13 @@ public class NewtFactoryAWT extends NewtFactory {
* @see #createScreen(java.awt.Component, boolean)
*/
public static MonitorDevice getMonitorDevice(final Screen screen, final java.awt.Component awtComp) throws IllegalArgumentException {
- checkComponentValid(awtComp);
+ final java.awt.GraphicsConfiguration gc = checkComponentValid(awtComp);
final String nwt = NativeWindowFactory.getNativeWindowType(true);
MonitorDevice res = null;
screen.addReference();
try {
if( NativeWindowFactory.TYPE_MACOSX == nwt ) {
- res = screen.getMonitor( JAWTUtil.getMonitorDisplayID( awtComp.getGraphicsConfiguration().getDevice() ) );
+ res = screen.getMonitor( JAWTUtil.getMonitorDisplayID( gc.getDevice() ) );
}
if( null == res ) {
// Fallback, use AWT component coverage