diff options
author | Sven Gothel <[email protected]> | 2015-07-27 20:00:06 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-07-27 20:00:06 +0200 |
commit | 6ae08be1742e6d805b316c0d440364854a49e68f (patch) | |
tree | 666866771aeb8fe880fd810f5a664e8e0315a6e9 /src/newt/classes | |
parent | 8e1f5fc43ba84d5e6373f0c29089ac32b7ce95dd (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.
Diffstat (limited to 'src/newt/classes')
-rw-r--r-- | src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java | 137 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java | 50 |
2 files changed, 175 insertions, 12 deletions
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 |