diff options
Diffstat (limited to 'src/nativewindow/classes/com/jogamp')
21 files changed, 1853 insertions, 493 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java new file mode 100644 index 000000000..c98bf5436 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java @@ -0,0 +1,39 @@ +package com.jogamp.nativewindow; + +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +public class DelegatedUpstreamSurfaceHookMutableSize extends UpstreamSurfaceHookMutableSize { + final UpstreamSurfaceHook upstream; + + /** + * @param upstream optional upstream UpstreamSurfaceHook used for {@link #create(ProxySurface)} and {@link #destroy(ProxySurface)}. + * @param width initial width + * @param height initial height + */ + public DelegatedUpstreamSurfaceHookMutableSize(UpstreamSurfaceHook upstream, int width, int height) { + super(width, height); + this.upstream = upstream; + } + + @Override + public final void create(ProxySurface s) { + if(null != upstream) { + upstream.create(s); + } + } + + @Override + public final void destroy(ProxySurface s) { + if(null != upstream) { + upstream.destroy(s); + } + } + + @Override + public String toString() { + return getClass().getSimpleName()+"[ "+ width + "x" + height + ", " + upstream + "]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java new file mode 100644 index 000000000..1557f4e51 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java @@ -0,0 +1,54 @@ +package com.jogamp.nativewindow; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +public class DelegatedUpstreamSurfaceHookWithSurfaceSize implements UpstreamSurfaceHook { + final UpstreamSurfaceHook upstream; + final NativeSurface surface; + + /** + * @param upstream optional upstream UpstreamSurfaceHook used for {@link #create(ProxySurface)} and {@link #destroy(ProxySurface)}. + * @param surface mandatory {@link NativeSurface} used for {@link #getWidth(ProxySurface)} and {@link #getHeight(ProxySurface)} + */ + public DelegatedUpstreamSurfaceHookWithSurfaceSize(UpstreamSurfaceHook upstream, NativeSurface surface) { + this.upstream = upstream; + this.surface = surface; + if(null == surface) { + throw new IllegalArgumentException("given surface is null"); + } + } + + @Override + public final void create(ProxySurface s) { + if(null != upstream) { + upstream.create(s); + } + } + + @Override + public final void destroy(ProxySurface s) { + if(null != upstream) { + upstream.destroy(s); + } + } + + @Override + public final int getWidth(ProxySurface s) { + return surface.getWidth(); + } + + @Override + public final int getHeight(ProxySurface s) { + return surface.getHeight(); + } + + @Override + public String toString() { + final String us_s = null != surface ? ( surface.getClass().getName() + ": 0x" + Long.toHexString(surface.getSurfaceHandle()) + " " +surface.getWidth() + "x" + surface.getHeight() ) : "nil"; + return getClass().getSimpleName()+"["+upstream+", "+us_s+"]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java index 2d5af86b9..8b8ccb191 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java @@ -37,7 +37,14 @@ public class MutableGraphicsConfiguration extends DefaultGraphicsConfiguration { super(screen, capsChosen, capsRequested); } + @Override public void setChosenCapabilities(CapabilitiesImmutable caps) { super.setChosenCapabilities(caps); } + + @Override + public void setScreen(AbstractGraphicsScreen screen) { + super.setScreen(screen); + } + } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowVersion.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowVersion.java index 38bd70a90..a8dd9165c 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowVersion.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowVersion.java @@ -3,14 +3,14 @@ * * 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 @@ -20,17 +20,18 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ - + package com.jogamp.nativewindow; import com.jogamp.common.GlueGenVersion; import com.jogamp.common.util.JogampVersion; import com.jogamp.common.util.VersionUtil; + import java.util.jar.Manifest; public class NativeWindowVersion extends JogampVersion { @@ -45,9 +46,10 @@ public class NativeWindowVersion extends JogampVersion { if(null == jogampCommonVersionInfo) { // volatile: ok synchronized(NativeWindowVersion.class) { if( null == jogampCommonVersionInfo ) { - final String packageName = "javax.media.nativewindow"; - final Manifest mf = VersionUtil.getManifest(NativeWindowVersion.class.getClassLoader(), packageName); - jogampCommonVersionInfo = new NativeWindowVersion(packageName, mf); + final String packageName1 = "javax.media.nativewindow"; // atomic packaging - and identity + final String packageName2 = "javax.media.opengl"; // all packaging + final Manifest mf = VersionUtil.getManifest(NativeWindowVersion.class.getClassLoader(), new String[]{ packageName1, packageName2 } ); + jogampCommonVersionInfo = new NativeWindowVersion(packageName1, mf); } } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java new file mode 100644 index 000000000..5838c7a56 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java @@ -0,0 +1,45 @@ +package com.jogamp.nativewindow; + +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +public class UpstreamSurfaceHookMutableSize implements UpstreamSurfaceHook.MutableSize { + int width, height; + + /** + * @param width initial width + * @param height initial height + */ + public UpstreamSurfaceHookMutableSize(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public final void setSize(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public final int getWidth(ProxySurface s) { + return width; + } + + @Override + public final int getHeight(ProxySurface s) { + return height; + } + @Override + public void create(ProxySurface s) { /* nop */ } + + @Override + public void destroy(ProxySurface s) { /* nop */ } + + @Override + public String toString() { + return getClass().getSimpleName()+"[ "+ width + "x" + height + "]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSizePos.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSizePos.java new file mode 100644 index 000000000..e6fcc049c --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSizePos.java @@ -0,0 +1,36 @@ +package com.jogamp.nativewindow; + +public class UpstreamSurfaceHookMutableSizePos extends UpstreamSurfaceHookMutableSize { + int x, y; + + /** + * @param width initial width + * @param height initial height + */ + public UpstreamSurfaceHookMutableSizePos(int x, int y, int width, int height) { + super(width, height); + this.x= x; + this.y= y; + } + + // @Override + public final void setPos(int x, int y) { + this.x= x; + this.y= y; + } + + public final int getX() { + return x; + } + + public final int getY() { + return y; + } + + @Override + public String toString() { + return getClass().getSimpleName()+"[ "+ x + "/" + y + " " + width + "x" + height + "]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java deleted file mode 100644 index f2993abab..000000000 --- a/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.nativewindow; - -import javax.media.nativewindow.AbstractGraphicsConfiguration; -import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.SurfaceChangeable; - - -public class WrappedSurface extends ProxySurface implements SurfaceChangeable { - protected long surfaceHandle; - - public WrappedSurface(AbstractGraphicsConfiguration cfg) { - this(cfg, 0); - } - - public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle) { - super(cfg); - surfaceHandle=handle; - } - - protected final void invalidateImpl() { - surfaceHandle = 0; - } - - final public long getSurfaceHandle() { - return surfaceHandle; - } - - final public void setSurfaceHandle(long surfaceHandle) { - this.surfaceHandle=surfaceHandle; - } - - final protected int lockSurfaceImpl() { - return LOCK_SUCCESS; - } - - final protected void unlockSurfaceImpl() { - } - - public String toString() { - return "WrappedSurface[config " + getPrivateGraphicsConfiguration()+ - ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + - ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + - ", size " + getWidth() + "x" + getHeight() + - ", surfaceLock "+surfaceLock+"]"; - } -} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java index 61d5e5c0d..aa9b876dd 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -57,7 +57,7 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple private GraphicsConfiguration config; AbstractGraphicsConfiguration encapsulated; - public AWTGraphicsConfiguration(AWTGraphicsScreen screen, + public AWTGraphicsConfiguration(AWTGraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, GraphicsConfiguration config, AbstractGraphicsConfiguration encapsulated) { super(screen, capsChosen, capsRequested); @@ -71,16 +71,17 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple this.config = config; this.encapsulated=null; } - + /** - * @param capsChosen if null, <code>capsRequested</code> is copied and aligned - * with the graphics Capabilities of the AWT Component to produce the chosen Capabilities. + * @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(Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { final GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration(); if(null==awtGfxConfig) { - throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp); + throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp); } final GraphicsDevice awtGraphicsDevice = awtGfxConfig.getDevice(); if(null==awtGraphicsDevice) { @@ -91,12 +92,15 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple final AWTGraphicsDevice awtDevice = new AWTGraphicsDevice(awtGraphicsDevice, AbstractGraphicsDevice.DEFAULT_UNIT); final AWTGraphicsScreen awtScreen = new AWTGraphicsScreen(awtDevice); + if(null==capsRequested) { + capsRequested = new Capabilities(); + } if(null==capsChosen) { GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsRequested, gc); } - final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice); - final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, null, awtScreen); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice, capsChosen); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, null, awtScreen, VisualIDHolder.VID_UNDEFINED); if(config instanceof AWTGraphicsConfiguration) { return (AWTGraphicsConfiguration) config; } @@ -105,10 +109,11 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple } // open access to superclass method + @Override public void setChosenCapabilities(CapabilitiesImmutable capsChosen) { super.setChosenCapabilities(capsChosen); } - + @Override public Object clone() { return super.clone(); @@ -167,7 +172,7 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple public String toString() { return getClass().getSimpleName()+"[" + getScreen() + ",\n\tchosen " + capabilitiesChosen+ - ",\n\trequested " + capabilitiesRequested+ + ",\n\trequested " + capabilitiesRequested+ ",\n\t" + config + ",\n\tencapsulated "+encapsulated+"]"; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsDevice.java index 635e6d263..a7fa53577 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsDevice.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsScreen.java index f4ee06e28..83d6efa75 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsScreen.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsScreen.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -87,6 +87,7 @@ public class AWTGraphicsScreen extends DefaultGraphicsScreen implements Cloneabl return new AWTGraphicsScreen(AWTGraphicsDevice.createDefault()); } + @Override public Object clone() { return super.clone(); } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTPrintLifecycle.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTPrintLifecycle.java new file mode 100644 index 000000000..44163fc73 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTPrintLifecycle.java @@ -0,0 +1,175 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.nativewindow.awt; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.PrinterJob; + +import jogamp.nativewindow.awt.AWTMisc; + +/** + * Interface describing print lifecycle to support AWT printing, + * e.g. on AWT {@link javax.media.opengl.GLAutoDrawable GLAutoDrawable}s. + * <a name="impl"><h5>Implementations</h5></a> + * <p> + * Implementing {@link javax.media.opengl.GLAutoDrawable GLAutoDrawable} classes based on AWT + * supporting {@link Component#print(Graphics)} shall implement this interface. + * </p> + * <a name="usage"><h5>Usage</h5></a> + * <p> + * Users attempting to print an AWT {@link Container} containing {@link AWTPrintLifecycle} elements + * shall consider decorating the {@link Container#printAll(Graphics)} call with<br> + * {@link #setupPrint(double, double, int, int, int) setupPrint(..)} and {@link #releasePrint()} + * on all {@link AWTPrintLifecycle} elements in the {@link Container}.<br> + * To minimize this burden, a user can use {@link Context#setupPrint(Container, double, double, int, int, int) Context.setupPrint(..)}: + * <pre> + * Container cont; + * double scaleGLMatXY = 72.0/glDPI; + * int numSamples = 0; // leave multisampling as-is + * PrinterJob job; + * ... + final AWTPrintLifecycle.Context ctx = AWTPrintLifecycle.Context.setupPrint(cont, scaleGLMatXY, scaleGLMatXY, numSamples); + try { + AWTEDTExecutor.singleton.invoke(true, new Runnable() { + public void run() { + try { + job.print(); + } catch (PrinterException ex) { + ex.printStackTrace(); + } + } }); + } finally { + ctx.releasePrint(); + } + * + * </pre> + * </p> + */ +public interface AWTPrintLifecycle { + + public static final int DEFAULT_PRINT_TILE_SIZE = 1024; + + + /** + * Shall be called before {@link PrinterJob#print()}. + * <p> + * See <a href="#usage">Usage</a>. + * </p> + * @param scaleMatX {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatX * width pixels + * @param scaleMatY {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatY * height pixels + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples + * @param tileWidth custom tile width for {@link com.jogamp.opengl.util.TileRenderer#setTileSize(int, int, int) tile renderer}, pass -1 for default. + * @param tileHeight custom tile height for {@link com.jogamp.opengl.util.TileRenderer#setTileSize(int, int, int) tile renderer}, pass -1 for default. + */ + void setupPrint(double scaleMatX, double scaleMatY, int numSamples, int tileWidth, int tileHeight); + + /** + * Shall be called after {@link PrinterJob#print()}. + * <p> + * See <a href="#usage">Usage</a>. + * </p> + */ + void releasePrint(); + + /** + * Convenient {@link AWTPrintLifecycle} context simplifying calling {@link AWTPrintLifecycle#setupPrint(double, double, int, int, int) setupPrint(..)} + * and {@link AWTPrintLifecycle#releasePrint()} on all {@link AWTPrintLifecycle} elements of a {@link Container}. + * <p> + * See <a href="#usage">Usage</a>. + * </p> + */ + public static class Context { + /** + * <p> + * See <a href="#usage">Usage</a>. + * </p> + * + * @param c container to be traversed through to perform {@link AWTPrintLifecycle#setupPrint(double, double, int, int, int) setupPrint(..)} on all {@link AWTPrintLifecycle} elements. + * @param scaleMatX {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatX * width pixels + * @param scaleMatY {@link Graphics2D} {@link Graphics2D#scale(double, double) scaling factor}, i.e. rendering 1/scaleMatY * height pixels + * @param numSamples multisampling value: < 0 turns off, == 0 leaves as-is, > 0 enables using given num samples + * @param tileWidth custom tile width for {@link TileRenderer#setTileSize(int, int, int) tile renderer}, pass -1 for default. + * @param tileHeight custom tile height for {@link TileRenderer#setTileSize(int, int, int) tile renderer}, pass -1 for default. + * @return the context + */ + public static Context setupPrint(Container c, double scaleMatX, double scaleMatY, int numSamples, int tileWidth, int tileHeight) { + final Context t = new Context(c, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight); + t.setupPrint(c); + return t; + } + + /** + * <p> + * See <a href="#usage">Usage</a>. + * </p> + */ + public void releasePrint() { + count = AWTMisc.performAction(cont, AWTPrintLifecycle.class, releaseAction); + } + + /** + * @return count of performed actions of last {@link #setupPrint(Container, double, double, int, int, int) setupPrint(..)} or {@link #releasePrint()}. + */ + public int getCount() { return count; } + + private final Container cont; + private final double scaleMatX; + private final double scaleMatY; + private final int numSamples; + private final int tileWidth; + private final int tileHeight; + private int count; + + private final AWTMisc.ComponentAction setupAction = new AWTMisc.ComponentAction() { + @Override + public void run(Component c) { + ((AWTPrintLifecycle)c).setupPrint(scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight); + } }; + private final AWTMisc.ComponentAction releaseAction = new AWTMisc.ComponentAction() { + @Override + public void run(Component c) { + ((AWTPrintLifecycle)c).releasePrint(); + } }; + + private Context(Container c, double scaleMatX, double scaleMatY, int numSamples, int tileWidth, int tileHeight) { + this.cont = c; + this.scaleMatX = scaleMatX; + this.scaleMatY = scaleMatY; + this.numSamples = numSamples; + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + this.count = 0; + } + private void setupPrint(Container c) { + count = AWTMisc.performAction(c, AWTPrintLifecycle.class, setupAction); + } + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTWindowClosingProtocol.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTWindowClosingProtocol.java index d78b4ac15..aadecb455 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTWindowClosingProtocol.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTWindowClosingProtocol.java @@ -33,22 +33,31 @@ import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; + import javax.media.nativewindow.WindowClosingProtocol; import jogamp.nativewindow.awt.AWTMisc; public class AWTWindowClosingProtocol implements WindowClosingProtocol { - private Component comp; - private Runnable closingOperation; - private volatile boolean closingListenerSet = false; - private Object closingListenerLock = new Object(); + private final Component comp; + private Window listenTo; + private final Runnable closingOperationClose; + private final Runnable closingOperationNOP; + private final Object closingListenerLock = new Object(); private WindowClosingMode defaultCloseOperation = WindowClosingMode.DISPOSE_ON_CLOSE; private boolean defaultCloseOperationSetByUser = false; - public AWTWindowClosingProtocol(Component comp, Runnable closingOperation) { + /** + * @param comp mandatory AWT component which AWT Window is being queried by parent traversal + * @param closingOperationClose mandatory closing operation, triggered if windowClosing and {@link WindowClosingMode#DISPOSE_ON_CLOSE} + * @param closingOperationNOP optional closing operation, triggered if windowClosing and {@link WindowClosingMode#DO_NOTHING_ON_CLOSE} + */ + public AWTWindowClosingProtocol(Component comp, Runnable closingOperationClose, Runnable closingOperationNOP) { this.comp = comp; - this.closingOperation = closingOperation; + this.listenTo = null; + this.closingOperationClose = closingOperationClose; + this.closingOperationNOP = closingOperationNOP; } class WindowClosingAdapter extends WindowAdapter { @@ -59,54 +68,46 @@ public class AWTWindowClosingProtocol implements WindowClosingProtocol { if( WindowClosingMode.DISPOSE_ON_CLOSE == op ) { // we have to issue this call right away, // otherwise the window gets destroyed - closingOperation.run(); + closingOperationClose.run(); + } else if( null != closingOperationNOP ){ + closingOperationNOP.run(); } } } WindowListener windowClosingAdapter = new WindowClosingAdapter(); - final boolean addClosingListenerImpl() { - Window w = AWTMisc.getWindow(comp); - if(null!=w) { - w.addWindowListener(windowClosingAdapter); - return true; - } - return false; - } - /** - * Adds this closing listener to the components Window if exist and only one time.<br> - * Hence you may call this method every time to ensure it has been set, - * ie in case the Window parent is not available yet. + * Adds this closing listener to the components Window if exist and only one time. + * <p> + * If the closing listener is already added, and {@link IllegalStateException} is thrown. + * </p> * - * @return + * @return true if added, otherwise false. + * @throws IllegalStateException */ - public final boolean addClosingListenerOneShot() { - if(!closingListenerSet) { // volatile: ok + public final boolean addClosingListener() throws IllegalStateException { synchronized(closingListenerLock) { - if(!closingListenerSet) { - closingListenerSet=addClosingListenerImpl(); - return closingListenerSet; - } + if(null != listenTo) { + throw new IllegalStateException("WindowClosingListener already set"); + } + listenTo = AWTMisc.getWindow(comp); + if(null!=listenTo) { + listenTo.addWindowListener(windowClosingAdapter); + return true; + } } - } - return false; + return false; } public final boolean removeClosingListener() { - if(closingListenerSet) { // volatile: ok synchronized(closingListenerLock) { - if(closingListenerSet) { - Window w = AWTMisc.getWindow(comp); - if(null!=w) { - w.removeWindowListener(windowClosingAdapter); - closingListenerSet = false; - return true; - } - } + if(null != listenTo) { + listenTo.removeWindowListener(windowClosingAdapter); + listenTo = null; + return true; + } } - } - return false; + return false; } /** @@ -115,6 +116,7 @@ public class AWTWindowClosingProtocol implements WindowClosingProtocol { * otherwise return the AWT/Swing close operation value translated to * a {@link WindowClosingProtocol} value . */ + @Override public final WindowClosingMode getDefaultCloseOperation() { synchronized(closingListenerLock) { if(defaultCloseOperationSetByUser) { @@ -125,6 +127,7 @@ public class AWTWindowClosingProtocol implements WindowClosingProtocol { return AWTMisc.getNWClosingOperation(comp); } + @Override public final WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) { synchronized(closingListenerLock) { final WindowClosingMode _op = defaultCloseOperation; diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java new file mode 100644 index 000000000..eeec66376 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java @@ -0,0 +1,297 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.nativewindow.awt; + +import java.awt.Point; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.nio.IntBuffer; +import java.util.Hashtable; + +import com.jogamp.common.nio.Buffers; + +/** + * {@link DataBuffer} specialization using NIO direct buffer of type {@link DataBuffer#TYPE_INT} as storage. + */ +public final class DirectDataBufferInt extends DataBuffer { + + public static class DirectWritableRaster extends WritableRaster { + protected DirectWritableRaster(SampleModel sampleModel, DirectDataBufferInt dataBuffer, Point origin) { + super(sampleModel, dataBuffer, origin); + } + } + + public static class BufferedImageInt extends BufferedImage { + final int customImageType; + public BufferedImageInt (int customImageType, ColorModel cm, WritableRaster raster, Hashtable<?,?> properties) { + super(cm, raster, false /* isRasterPremultiplied */, properties); + this.customImageType = customImageType; + } + + /** + * @return one of the custom image-type values {@link BufferedImage#TYPE_INT_ARGB TYPE_INT_ARGB}, + * {@link BufferedImage#TYPE_INT_ARGB_PRE TYPE_INT_ARGB_PRE}, + * {@link BufferedImage#TYPE_INT_RGB TYPE_INT_RGB} or {@link BufferedImage#TYPE_INT_BGR TYPE_INT_BGR}. + */ + public int getCustomType() { + return customImageType; + } + + @Override + public String toString() { + return "BufferedImageInt@"+Integer.toHexString(hashCode()) + +": custom/internal type = "+customImageType+"/"+getType() + +" "+getColorModel()+" "+getRaster(); + } + } + + /** + * Creates a {@link BufferedImageInt} using a {@link DirectColorModel direct color model} in {@link ColorSpace#CS_sRGB sRGB color space}.<br> + * It uses a {@link DirectWritableRaster} utilizing {@link DirectDataBufferInt} storage. + * <p> + * Note that due to using the custom storage type {@link DirectDataBufferInt}, the resulting + * {@link BufferedImage}'s {@link BufferedImage#getType() image-type} is of {@link BufferedImage#TYPE_CUSTOM TYPE_CUSTOM}. + * We are not able to change this detail, since the AWT image implementation associates the {@link BufferedImage#getType() image-type} + * with a build-in storage-type. + * Use {@link BufferedImageInt#getCustomType()} to retrieve the custom image-type, which will return the <code>imageType</code> + * value passed here. + * </p> + * + * @param width + * @param height + * @param imageType one of {@link BufferedImage#TYPE_INT_ARGB TYPE_INT_ARGB}, {@link BufferedImage#TYPE_INT_ARGB_PRE TYPE_INT_ARGB_PRE}, + * {@link BufferedImage#TYPE_INT_RGB TYPE_INT_RGB} or {@link BufferedImage#TYPE_INT_BGR TYPE_INT_BGR}. + * @param location origin, if <code>null</code> 0/0 is assumed. + * @param properties <code>Hashtable</code> of + * <code>String</code>/<code>Object</code> pairs. Used for {@link BufferedImage#getProperty(String)} etc. + * @return + */ + public static BufferedImageInt createBufferedImage(int width, int height, int imageType, Point location, Hashtable<?,?> properties) { + final ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); + final int transferType = DataBuffer.TYPE_INT; + final int bpp, rmask, gmask, bmask, amask; + final boolean alphaPreMul; + switch( imageType ) { + case BufferedImage.TYPE_INT_ARGB: + bpp = 32; + rmask = 0x00ff0000; + gmask = 0x0000ff00; + bmask = 0x000000ff; + amask = 0xff000000; + alphaPreMul = false; + break; + case BufferedImage.TYPE_INT_ARGB_PRE: + bpp = 32; + rmask = 0x00ff0000; + gmask = 0x0000ff00; + bmask = 0x000000ff; + amask = 0xff000000; + alphaPreMul = true; + break; + case BufferedImage.TYPE_INT_RGB: + bpp = 24; + rmask = 0x00ff0000; + gmask = 0x0000ff00; + bmask = 0x000000ff; + amask = 0x0; + alphaPreMul = false; + break; + case BufferedImage.TYPE_INT_BGR: + bpp = 24; + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0x0; + alphaPreMul = false; + break; + default: + throw new IllegalArgumentException("Unsupported imageType, must be [INT_ARGB, INT_ARGB_PRE, INT_RGB, INT_BGR], has "+imageType); + } + final ColorModel colorModel = new DirectColorModel(colorSpace, bpp, rmask, gmask, bmask, amask, alphaPreMul, transferType); + final int[] bandMasks; + if ( 0 != amask ) { + bandMasks = new int[4]; + bandMasks[3] = amask; + } + else { + bandMasks = new int[3]; + } + bandMasks[0] = rmask; + bandMasks[1] = gmask; + bandMasks[2] = bmask; + + final DirectDataBufferInt dataBuffer = new DirectDataBufferInt(width*height); + if( null == location ) { + location = new Point(0,0); + } + final SinglePixelPackedSampleModel sppsm = new SinglePixelPackedSampleModel(dataBuffer.getDataType(), + width, height, width /* scanLineStride */, bandMasks); + // IntegerComponentRasters must haveinteger DataBuffers: + // final WritableRaster raster = new IntegerInterleavedRaster(sppsm, dataBuffer, location); + // Not public: + // final WritableRaster raster = new SunWritableRaster(sppsm, dataBuffer, location); + final WritableRaster raster = new DirectWritableRaster(sppsm, dataBuffer, location); + + return new BufferedImageInt(imageType, colorModel, raster, properties); + } + + /** Default data bank. */ + private IntBuffer data; + + /** All data banks */ + private IntBuffer bankdata[]; + + /** + * Constructs an nio integer-based {@link DataBuffer} with a single bank + * and the specified size. + * + * @param size The size of the {@link DataBuffer}. + */ + public DirectDataBufferInt(int size) { + super(TYPE_INT, size); + data = Buffers.newDirectIntBuffer(size); + bankdata = new IntBuffer[1]; + bankdata[0] = data; + } + + /** + * Constructs an nio integer-based {@link DataBuffer} with the specified number of + * banks, all of which are the specified size. + * + * @param size The size of the banks in the {@link DataBuffer}. + * @param numBanks The number of banks in the a{@link DataBuffer}. + */ + public DirectDataBufferInt(int size, int numBanks) { + super(TYPE_INT,size,numBanks); + bankdata = new IntBuffer[numBanks]; + for (int i= 0; i < numBanks; i++) { + bankdata[i] = Buffers.newDirectIntBuffer(size); + } + data = bankdata[0]; + } + + /** + * Constructs an nio integer-based {@link DataBuffer} with a single bank using the + * specified array. + * <p> + * Only the first <code>size</code> elements should be used by accessors of + * this {@link DataBuffer}. <code>dataArray</code> must be large enough to + * hold <code>size</code> elements. + * </p> + * + * @param dataArray The integer array for the {@link DataBuffer}. + * @param size The size of the {@link DataBuffer} bank. + */ + public DirectDataBufferInt(IntBuffer dataArray, int size) { + super(TYPE_INT,size); + data = dataArray; + bankdata = new IntBuffer[1]; + bankdata[0] = data; + } + + /** + * Returns the default (first) int data array in {@link DataBuffer}. + * + * @return The first integer data array. + */ + public IntBuffer getData() { + return data; + } + + /** + * Returns the data array for the specified bank. + * + * @param bank The bank whose data array you want to get. + * @return The data array for the specified bank. + */ + public IntBuffer getData(int bank) { + return bankdata[bank]; + } + + /** + * Returns the requested data array element from the first (default) bank. + * + * @param i The data array element you want to get. + * @return The requested data array element as an integer. + * @see #setElem(int, int) + * @see #setElem(int, int, int) + */ + @Override + public int getElem(int i) { + return data.get(i+offset); + } + + /** + * Returns the requested data array element from the specified bank. + * + * @param bank The bank from which you want to get a data array element. + * @param i The data array element you want to get. + * @return The requested data array element as an integer. + * @see #setElem(int, int) + * @see #setElem(int, int, int) + */ + @Override + public int getElem(int bank, int i) { + return bankdata[bank].get(i+offsets[bank]); + } + + /** + * Sets the requested data array element in the first (default) bank + * to the specified value. + * + * @param i The data array element you want to set. + * @param val The integer value to which you want to set the data array element. + * @see #getElem(int) + * @see #getElem(int, int) + */ + @Override + public void setElem(int i, int val) { + data.put(i+offset, val); + } + + /** + * Sets the requested data array element in the specified bank + * to the integer value <code>i</code>. + * @param bank The bank in which you want to set the data array element. + * @param i The data array element you want to set. + * @param val The integer value to which you want to set the specified data array element. + * @see #getElem(int) + * @see #getElem(int, int) + */ + @Override + public void setElem(int bank, int i, int val) { + bankdata[bank].put(i+offsets[bank], val); + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 02dd746a0..20ab7a2ee 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,7 +29,7 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. @@ -37,14 +37,25 @@ package com.jogamp.nativewindow.awt; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.nativewindow.MutableGraphicsConfiguration; import java.awt.Component; import java.awt.Container; +import java.awt.Cursor; +import java.awt.Window; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; import java.applet.Applet; + import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; @@ -53,11 +64,14 @@ import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.nativewindow.util.PixelRectangle; import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.PointImmutable; import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; import jogamp.nativewindow.SurfaceUpdatedHelper; +import jogamp.nativewindow.awt.AWTMisc; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWT_Rectangle; @@ -67,12 +81,13 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, // user properties protected boolean shallUseOffscreenLayer = false; - + // lifetime: forever - protected Component component; - private AWTGraphicsConfiguration config; // control access due to delegation - private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + protected final Component component; + 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; // lifetime: valid after lock but may change with each 1st lock, purges after invalidate private boolean isApplet; @@ -81,13 +96,14 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected long drawable; protected Rectangle bounds; protected Insets insets; - + private volatile long offscreenSurfaceLayer; + private long drawable_old; - + /** * Constructed by {@link jogamp.nativewindow.NativeWindowFactoryImpl#getNativeWindow(Object, AbstractGraphicsConfiguration)} * via this platform's specialization (X11, OSX, Windows, ..). - * + * * @param comp * @param config */ @@ -98,29 +114,142 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, if(! ( config instanceof AWTGraphicsConfiguration ) ) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config); } + this.component = (Component)comp; this.config = (AWTGraphicsConfiguration) config; - init((Component)comp); - } - - private void init(Component windowObject) throws NativeWindowException { + this.jawtComponentListener = new JAWTComponentListener(); invalidate(); - this.component = windowObject; this.isApplet = false; + this.offscreenSurfaceLayer = 0; + } + private static String id(Object obj) { return "0x" + ( null!=obj ? Integer.toHexString(obj.hashCode()) : "nil" ); } + private String jawtStr() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; } + + private class JAWTComponentListener implements ComponentListener, HierarchyListener { + private boolean isShowing; + + private String str(final Object obj) { + if( null == obj ) { + return "0xnil: null"; + } else if( obj instanceof Component ) { + final Component c = (Component)obj; + return id(obj)+": "+c.getClass().getSimpleName()+"[visible "+c.isVisible()+", showing "+c.isShowing()+", valid "+c.isValid()+ + ", displayable "+c.isDisplayable()+", "+c.getX()+"/"+c.getY()+" "+c.getWidth()+"x"+c.getHeight()+"]"; + } else { + return id(obj)+": "+obj.getClass().getSimpleName()+"[..]"; + } + } + private String s(final ComponentEvent e) { + return "visible[isShowing "+isShowing+"],"+Platform.getNewline()+ + " ** COMP "+str(e.getComponent())+Platform.getNewline()+ + " ** SOURCE "+str(e.getSource())+Platform.getNewline()+ + " ** THIS "+str(component)+Platform.getNewline()+ + " ** THREAD "+getThreadName(); + } + private String s(final HierarchyEvent e) { + return "visible[isShowing "+isShowing+"], changeBits 0x"+Long.toHexString(e.getChangeFlags())+Platform.getNewline()+ + " ** COMP "+str(e.getComponent())+Platform.getNewline()+ + " ** SOURCE "+str(e.getSource())+Platform.getNewline()+ + " ** CHANGED "+str(e.getChanged())+Platform.getNewline()+ + " ** CHANGEDPARENT "+str(e.getChangedParent())+Platform.getNewline()+ + " ** THIS "+str(component)+Platform.getNewline()+ + " ** THREAD "+getThreadName(); + } + @Override + public final String toString() { + return "visible[isShowing "+isShowing+"],"+Platform.getNewline()+ + " ** THIS "+str(component)+Platform.getNewline()+ + " ** THREAD "+getThreadName(); + } + + private JAWTComponentListener() { + isShowing = component.isShowing(); + AWTEDTExecutor.singleton.invoke(false, new Runnable() { // Bug 952: Avoid deadlock via AWTTreeLock acquisition .. + @Override + public void run() { + if(DEBUG) { + System.err.println(jawtStr()+".attach @ Thread "+getThreadName()+": "+JAWTComponentListener.this.toString()); + } + component.addComponentListener(JAWTComponentListener.this); + component.addHierarchyListener(JAWTComponentListener.this); + } } ); + } + + private final void detach() { + AWTEDTExecutor.singleton.invoke(false, new Runnable() { // Bug 952: Avoid deadlock via AWTTreeLock acquisition .. + @Override + public void run() { + if(DEBUG) { + System.err.println(jawtStr()+".detach @ Thread "+getThreadName()+": "+JAWTComponentListener.this.toString()); + } + component.removeComponentListener(JAWTComponentListener.this); + component.removeHierarchyListener(JAWTComponentListener.this); + } } ); + } + + @Override + public final void componentResized(ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentResized: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void componentMoved(ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentMoved: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void componentShown(ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentShown: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void componentHidden(ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentHidden: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void hierarchyChanged(HierarchyEvent e) { + final boolean wasShowing = isShowing; + isShowing = component.isShowing(); + int action = 0; + if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags() ) ) { + if( e.getChanged() != component && wasShowing != isShowing ) { + // A parent component changed and caused a 'showing' state change, + // propagate to offscreen-layer! + layoutSurfaceLayerIfEnabled(isShowing); + action = 1; + } + } + if(DEBUG) { + final java.awt.Component changed = e.getChanged(); + final boolean displayable = changed.isDisplayable(); + final boolean showing = changed.isShowing(); + System.err.println(jawtStr()+".hierarchyChanged: action "+action+", displayable "+displayable+", showing [changed "+showing+", comp "+isShowing+"], "+s(e)); + } + } } - - public void setShallUseOffscreenLayer(boolean v) { - shallUseOffscreenLayer = v; - } - - public final boolean getShallUseOffscreenLayer() { - return shallUseOffscreenLayer; - } - - public final boolean isOffscreenLayerSurfaceEnabled() { - return isOffscreenLayerSurface; - } - + + private static String getThreadName() { return Thread.currentThread().getName(); } + protected synchronized void invalidate() { + if(DEBUG) { + System.err.println(jawtStr()+".invalidate() - "+jawtComponentListener.toString()); + if( isSurfaceLayerAttached() ) { + System.err.println("OffscreenSurfaceLayer still attached: 0x"+Long.toHexString(offscreenSurfaceLayer)); + } + // Thread.dumpStack(); + } invalidateNative(); jawt = null; isOffscreenLayerSurface = false; @@ -131,33 +260,38 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } protected abstract void invalidateNative(); - protected final void updateBounds(JAWT_Rectangle jawtBounds) { - bounds.setX(jawtBounds.getX()); - bounds.setY(jawtBounds.getY()); - bounds.setWidth(jawtBounds.getWidth()); - bounds.setHeight(jawtBounds.getHeight()); - - if(component instanceof Container) { - java.awt.Insets contInsets = ((Container)component).getInsets(); - insets.setLeftWidth(contInsets.left); - insets.setRightWidth(contInsets.right); - insets.setTopHeight(contInsets.top); - insets.setBottomHeight(contInsets.bottom); + protected final boolean updateBounds(JAWT_Rectangle jawtBounds) { + final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight()); + final boolean changed = !bounds.equals(jb); + + if(changed) { + if(DEBUG) { + System.err.println("JAWTWindow.updateBounds: "+bounds+" -> "+jb); + // Thread.dumpStack(); + } + bounds.set(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight()); + + if(component instanceof Container) { + final java.awt.Insets contInsets = ((Container)component).getInsets(); + insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom); + } } + return changed; } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } - + + @Override public final InsetsImmutable getInsets() { return insets; } public final Component getAWTComponent() { return component; } - - /** - * Returns true if the AWT component is parented to an {@link java.applet.Applet}, - * otherwise false. This information is valid only after {@link #lockSurface()}. + + /** + * Returns true if the AWT component is parented to an {@link java.applet.Applet}, + * otherwise false. This information is valid only after {@link #lockSurface()}. */ public final boolean isApplet() { return isApplet; @@ -168,70 +302,141 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return jawt; } - /** - * {@inheritDoc} - */ - public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException { + // + // OffscreenLayerOption + // + + @Override + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + @Override + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + @Override + public final boolean isOffscreenLayerSurfaceEnabled() { + return isOffscreenLayerSurface; + } + + // + // OffscreenLayerSurface + // + + @Override + public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException { if( !isOffscreenLayerSurfaceEnabled() ) { throw new NativeWindowException("Not an offscreen layer surface"); } - int lockRes = lockSurface(); - if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { - throw new NativeWindowException("Could not lock (offscreen layer): "+this); - } - try { - if(DEBUG) { - System.err.println("JAWTWindow.attachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); - } - attachSurfaceLayerImpl(layerHandle); - } finally { - unlockSurface(); - } - } - protected abstract void attachSurfaceLayerImpl(final long layerHandle); - - /** - * {@inheritDoc} + attachSurfaceLayerImpl(layerHandle); + offscreenSurfaceLayer = layerHandle; + component.repaint(); + } + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + + /** + * Layout the offscreen layer according to the implementing class's constraints. + * <p> + * This method allows triggering a re-layout of the offscreen surface + * in case the implementation requires it. + * </p> + * <p> + * Call this method if any parent or ancestor's layout has been changed, + * which could affects the layout of this surface. + * </p> + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false */ - public final void detachSurfaceLayer(final long layerHandle) throws NativeWindowException { - if( !isOffscreenLayerSurfaceEnabled() ) { - throw new java.lang.UnsupportedOperationException("Not an offscreen layer surface"); + protected void layoutSurfaceLayerImpl(long layerHandle, boolean visible) {} + + private final void layoutSurfaceLayerIfEnabled(boolean visible) throws NativeWindowException { + if( isOffscreenLayerSurfaceEnabled() && 0 != offscreenSurfaceLayer ) { + layoutSurfaceLayerImpl(offscreenSurfaceLayer, visible); } - int lockRes = lockSurface(); - if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { - throw new NativeWindowException("Could not lock (offscreen layer): "+this); + } + + + @Override + public final void detachSurfaceLayer() throws NativeWindowException { + if( 0 == offscreenSurfaceLayer) { + throw new NativeWindowException("No offscreen layer attached: "+this); } - try { - if(DEBUG) { - System.err.println("JAWTWindow.detachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); - } - detachSurfaceLayerImpl(layerHandle); - } finally { - unlockSurface(); + if(DEBUG) { + System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer)); } - } - protected abstract void detachSurfaceLayerImpl(final long layerHandle); - - // - // SurfaceUpdateListener - // + detachSurfaceLayerImpl(offscreenSurfaceLayer, detachSurfaceLayerNotify); + } + private final Runnable detachSurfaceLayerNotify = new Runnable() { + @Override + public void run() { + offscreenSurfaceLayer = 0; + } + }; - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - surfaceUpdatedHelper.addSurfaceUpdatedListener(l); + /** + * @param detachNotify Runnable to be called before native detachment + */ + protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) { + throw new UnsupportedOperationException("offscreen layer not supported"); } - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { - surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + + @Override + public final long getAttachedSurfaceLayer() { + return offscreenSurfaceLayer; } - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + @Override + public final boolean isSurfaceLayerAttached() { + return 0 != offscreenSurfaceLayer; + } + + @Override + public final void setChosenCapabilities(CapabilitiesImmutable caps) { + ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); + config.setChosenCapabilities(caps); + } + + @Override + public final RecursiveLock getLock() { + return surfaceLock; + } + + @Override + public final boolean setCursor(final PixelRectangle pixelrect, final PointImmutable hotSpot) { + AWTEDTExecutor.singleton.invoke(false, new Runnable() { + public void run() { + Cursor c = null; + if( null == pixelrect || null == hotSpot ) { + c = Cursor.getDefaultCursor(); + } else { + final java.awt.Point awtHotspot = new java.awt.Point(hotSpot.getX(), hotSpot.getY()); + try { + c = AWTMisc.getCursor(pixelrect, awtHotspot); + } catch (Exception e) { + e.printStackTrace(); + } + } + if( null != c ) { + component.setCursor(c); + } + } } ); + return true; + } + + @Override + public final boolean hideCursor() { + AWTEDTExecutor.singleton.invoke(false, new Runnable() { + public void run() { + component.setCursor(AWTMisc.getNullCursor()); + } } ); + return true; } - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { - surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); - } - // // NativeSurface // @@ -243,59 +448,65 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, c = c.getParent(); } } - + /** - * If JAWT offscreen layer is supported, + * If JAWT offscreen layer is supported, * implementation shall respect {@link #getShallUseOffscreenLayer()} * and may respect {@link #isApplet()}. - * + * * @return The JAWT instance reflecting offscreen layer support, etc. - * + * * @throws NativeWindowException */ protected abstract JAWT fetchJAWTImpl() throws NativeWindowException; protected abstract int lockSurfaceImpl() throws NativeWindowException; protected void dumpJAWTInfo() { - if(null != jawt) { - System.err.println("JAWT version: 0x"+Integer.toHexString(jawt.getCachedVersion())+ - ", CA_LAYER: "+ JAWTUtil.isJAWTUsingOffscreenLayer(jawt)+ - ", isLayeredSurface "+isOffscreenLayerSurfaceEnabled()+", bounds "+bounds+", insets "+insets); - } else { - System.err.println("JAWT n/a, bounds "+bounds+", insets "+insets); - } + System.err.println(jawt2String(null).toString()); // Thread.dumpStack(); } - - public final int lockSurface() throws NativeWindowException { + + @Override + public final int lockSurface() throws NativeWindowException, RuntimeException { surfaceLock.lock(); int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { - determineIfApplet(); - try { - final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); - adevice.lock(); + if( !component.isDisplayable() ) { + // W/o native peer, we cannot utilize JAWT for locking. + surfaceLock.unlock(); + if(DEBUG) { + System.err.println("JAWTWindow: Can't lock surface, component peer n/a. Component displayable "+component.isDisplayable()+", "+component); + Thread.dumpStack(); + } + } else { + determineIfApplet(); try { - jawt = fetchJAWTImpl(); - isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); - res = lockSurfaceImpl(); - if(LOCK_SUCCESS == res && drawable_old != drawable) { - res = LOCK_SURFACE_CHANGED; - if(DEBUG) { - System.err.println("JAWTWindow: surface change 0x"+Long.toHexString(drawable_old)+" -> 0x"+Long.toHexString(drawable)); - // Thread.dumpStack(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); + adevice.lock(); + try { + if(null == jawt) { // no need to re-fetch for each frame + jawt = fetchJAWTImpl(); + isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); + } + res = lockSurfaceImpl(); + if(LOCK_SUCCESS == res && drawable_old != drawable) { + res = LOCK_SURFACE_CHANGED; + if(DEBUG) { + System.err.println("JAWTWindow: surface change "+toHexString(drawable_old)+" -> "+toHexString(drawable)); + // Thread.dumpStack(); + } + } + } finally { + if (LOCK_SURFACE_NOT_READY >= res) { + adevice.unlock(); } } } finally { if (LOCK_SURFACE_NOT_READY >= res) { - adevice.unlock(); + surfaceLock.unlock(); } } - } finally { - if (LOCK_SURFACE_NOT_READY >= res) { - surfaceLock.unlock(); - } } } return res; @@ -303,6 +514,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected abstract void unlockSurfaceImpl() throws NativeWindowException; + @Override public final void unlockSurface() { surfaceLock.validateLocked(); drawable_old = drawable; @@ -310,7 +522,9 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, if (surfaceLock.getHoldCount() == 1) { final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { - unlockSurfaceImpl(); + if(null != jawt) { + unlockSurfaceImpl(); + } } finally { adevice.unlock(); } @@ -318,47 +532,68 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, surfaceLock.unlock(); } + @Override public final boolean isSurfaceLockedByOtherThread() { return surfaceLock.isLockedByOtherThread(); } - public final boolean isSurfaceLocked() { - return surfaceLock.isLocked(); - } - + @Override public final Thread getSurfaceLockOwner() { return surfaceLock.getOwner(); } + @Override public boolean surfaceSwap() { return false; } + @Override + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); + } + + @Override + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + @Override + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + @Override + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } + + @Override public long getSurfaceHandle() { return drawable; } - - public final AWTGraphicsConfiguration getPrivateGraphicsConfiguration() { - return config; - } - + + @Override public final AbstractGraphicsConfiguration getGraphicsConfiguration() { return config.getNativeGraphicsConfiguration(); } + @Override public final long getDisplayHandle() { return getGraphicsConfiguration().getScreen().getDevice().getHandle(); } + @Override public final int getScreenIndex() { return getGraphicsConfiguration().getScreen().getIndex(); } - public int getWidth() { + @Override + public final int getWidth() { return component.getWidth(); } - public int getHeight() { + @Override + public final int getHeight() { return component.getHeight(); } @@ -366,41 +601,55 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, // NativeWindow // - public synchronized void destroy() { - invalidate(); - component = null; // don't dispose the AWT component, since we are merely an immutable uplink + @Override + public void destroy() { + surfaceLock.lock(); + try { + if(DEBUG) { + System.err.println(jawtStr()+".destroy @ Thread "+getThreadName()); + } + jawtComponentListener.detach(); + invalidate(); + } finally { + surfaceLock.unlock(); + } } + @Override public final NativeWindow getParent() { return null; } + @Override public long getWindowHandle() { return drawable; } - + + @Override public final int getX() { return component.getX(); } + @Override public final int getY() { return component.getY(); } - + /** * {@inheritDoc} - * + * * <p> - * This JAWT default implementation is currently still using + * This JAWT default implementation is currently still using * a blocking implementation. It first attempts to retrieve the location * via a native implementation. If this fails, it tries the blocking AWT implementation. - * If the latter fails due to an external AWT tree-lock, the non block + * If the latter fails due to an external AWT tree-lock, the non block * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used. * The latter simply traverse up to the AWT component tree and sums the rel. position. * We have to determine whether the latter is good enough for all cases, * currently only OS X utilizes the non blocking method per default. - * </p> + * </p> */ + @Override public Point getLocationOnScreen(Point storage) { Point los = getLocationOnScreenNative(storage); if(null == los) { @@ -410,7 +659,11 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this); Thread.dumpStack(); } - return getLocationOnScreenNonBlocking(storage, component); + if( null == storage ) { + storage = new Point(); + } + getLocationOnScreenNonBlocking(storage, component); + return storage; } java.awt.Point awtLOS = component.getLocationOnScreen(); if(null!=storage) { @@ -421,7 +674,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } return los; } - + protected Point getLocationOnScreenNative(Point storage) { int lockRes = lockSurface(); if(LOCK_SURFACE_NOT_READY == lockRes) { @@ -442,50 +695,84 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return d; } finally { unlockSurface(); - } + } } protected abstract Point getLocationOnScreenNativeImpl(int x, int y); - protected static Point getLocationOnScreenNonBlocking(Point storage, Component comp) { - int x = 0; - int y = 0; + protected static Component getLocationOnScreenNonBlocking(Point storage, Component comp) { + final java.awt.Insets insets = new java.awt.Insets(0, 0, 0, 0); // DEBUG + Component last = null; while(null != comp) { - x += comp.getX(); - y += comp.getY(); + final int dx = comp.getX(); + final int dy = comp.getY(); + if( DEBUG ) { + final java.awt.Insets ins = AWTMisc.getInsets(comp, false); + if( null != ins ) { + insets.bottom += ins.bottom; + insets.top += ins.top; + insets.left += ins.left; + insets.right += ins.right; + } + System.err.print("LOS: "+storage+" + "+comp.getClass().getName()+"["+dx+"/"+dy+", vis "+comp.isVisible()+", ins "+ins+" -> "+insets+"] -> "); + } + storage.translate(dx, dy); + if( DEBUG ) { + System.err.println(storage); + } + last = comp; + if( comp instanceof Window ) { // top-level heavy-weight ? + break; + } comp = comp.getParent(); } - if(null!=storage) { - storage.translate(x, y); - return storage; - } - return new Point(x, y); + return last; } - + + @Override public boolean hasFocus() { return component.hasFocus(); } - + + protected StringBuilder jawt2String(StringBuilder sb) { + if( null == sb ) { + sb = new StringBuilder(); + } + sb.append("JVM version: ").append(Platform.JAVA_VERSION).append(" ("). + append(Platform.JAVA_VERSION_NUMBER). + append(" update ").append(Platform.JAVA_VERSION_UPDATE).append(")").append(Platform.getNewline()); + if(null != jawt) { + sb.append("JAWT version: 0x").append(Integer.toHexString(jawt.getCachedVersion())). + append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)). + append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()).append(", bounds ").append(bounds).append(", insets ").append(insets); + } else { + sb.append("JAWT n/a, bounds ").append(bounds).append(", insets ").append(insets); + } + return sb; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("JAWT-Window["+ - "windowHandle 0x"+Long.toHexString(getWindowHandle())+ - ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", bounds "+bounds+", insets "+insets+ - ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface); - if(null!=component) { - sb.append(", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ - ", visible "+component.isVisible()); - } else { - sb.append(", component NULL"); - } + sb.append(jawtStr()+"["); + jawt2String(sb); + sb.append( ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface+ + ", attachedSurfaceLayer "+toHexString(getAttachedSurfaceLayer())+ + ", windowHandle "+toHexString(getWindowHandle())+ + ", surfaceHandle "+toHexString(getSurfaceHandle())+ + ", bounds "+bounds+", insets "+insets + ); + sb.append(", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ + ", visible "+component.isVisible()); sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ - ",\n\tconfig "+getPrivateGraphicsConfiguration()+ + ",\n\tconfig "+config+ ",\n\tawtComponent "+getAWTComponent()+ ",\n\tsurfaceLock "+surfaceLock+"]"); return sb.toString(); } + protected final String toHexString(long l) { + return "0x"+Long.toHexString(l); + } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java index 4ee336176..6dc52a702 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -36,25 +36,111 @@ import javax.media.nativewindow.*; /** Encapsulates a graphics device on EGL platforms. */ - public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - boolean closeDisplay = false; + final long[] nativeDisplayID = new long[1]; + /* final */ EGLDisplayLifecycleCallback eglLifecycleCallback; + + /** + * Hack to allow inject a EGL termination call. + * <p> + * FIXME: This shall be removed when relocated EGL to the nativewindow package, + * since then it can be utilized directly. + * </p> + */ + public interface EGLDisplayLifecycleCallback { + /** + * Implementation should issue an <code>EGL.eglGetDisplay(nativeDisplayID)</code> + * inclusive <code>EGL.eglInitialize(eglDisplayHandle, ..)</code> call. + * @param nativeDisplayID in/out array of size 1, passing the requested nativeVisualID, may return a different revised nativeVisualID handle + * @return the initialized EGL display ID, or <code>0</code> if not successful + */ + public long eglGetAndInitDisplay(long[] nativeDisplayID); + + /** + * Implementation should issue an <code>EGL.eglTerminate(eglDisplayHandle)</code> call. + * @param eglDisplayHandle + */ + void eglTerminate(long eglDisplayHandle); + } /** * Note that this is not an open connection, ie no native display handle exist. * This constructor exist to setup a default device connection/unit.<br> */ - public EGLGraphicsDevice(String connection, int unitID) { - super(NativeWindowFactory.TYPE_EGL, connection, unitID); + public EGLGraphicsDevice() { + super(NativeWindowFactory.TYPE_EGL, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + this.nativeDisplayID[0] = 0 ; // EGL.EGL_DEFAULT_DISPLAY + this.eglLifecycleCallback = null; } - /** Constructs a new EGLGraphicsDevice corresponding to the given EGL display handle. */ - public EGLGraphicsDevice(long eglDisplay, String connection, int unitID) { + public EGLGraphicsDevice(long nativeDisplayID, long eglDisplay, String connection, int unitID, EGLDisplayLifecycleCallback eglLifecycleCallback) { super(NativeWindowFactory.TYPE_EGL, connection, unitID, eglDisplay); + this.nativeDisplayID[0] = nativeDisplayID; + this.eglLifecycleCallback = eglLifecycleCallback; } - + + public long getNativeDisplayID() { return nativeDisplayID[0]; } + + @Override public Object clone() { return super.clone(); } + + /** + * Opens the EGL device if handle is null and it's {@link EGLDisplayLifecycleCallback} is valid. + * <p> + * {@inheritDoc} + * </p> + */ + @Override + public boolean open() { + if(null != eglLifecycleCallback && 0 == handle) { + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - EGLGraphicsDevice.open(): "+this); + } + handle = eglLifecycleCallback.eglGetAndInitDisplay(nativeDisplayID); + if(0 == handle) { + throw new NativeWindowException("EGLGraphicsDevice.open() failed: "+this); + } + return true; + } + return false; + } + + /** + * Closes the EGL device if handle is not null and it's {@link EGLDisplayLifecycleCallback} is valid. + * <p> + * {@inheritDoc} + * </p> + */ + @Override + public boolean close() { + if(null != eglLifecycleCallback && 0 != handle) { + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - EGLGraphicsDevice.close(): "+this); + } + eglLifecycleCallback.eglTerminate(handle); + } + return super.close(); + } + + @Override + public boolean isHandleOwner() { + return null != eglLifecycleCallback; + } + @Override + public void clearHandleOwner() { + eglLifecycleCallback = null; + } + @Override + protected Object getHandleOwnership() { + return eglLifecycleCallback; + } + @Override + protected Object setHandleOwnership(Object newOwnership) { + final EGLDisplayLifecycleCallback oldOwnership = eglLifecycleCallback; + eglLifecycleCallback = (EGLDisplayLifecycleCallback) newOwnership; + return oldOwnership; + } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/macosx/MacOSXGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/macosx/MacOSXGraphicsDevice.java index 0dc788c17..99ca006fa 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/macosx/MacOSXGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/macosx/MacOSXGraphicsDevice.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -43,6 +43,7 @@ public class MacOSXGraphicsDevice extends DefaultGraphicsDevice implements Clone super(NativeWindowFactory.TYPE_MACOSX, AbstractGraphicsDevice.DEFAULT_CONNECTION, unitID); } + @Override public Object clone() { return super.clone(); } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java index f4309617b..36bf646d5 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java @@ -30,62 +30,119 @@ package com.jogamp.nativewindow.swt; import com.jogamp.common.os.Platform; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; +import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.VisualIDHolder; + import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.VersionNumber; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.nativewindow.x11.X11Lib; public class SWTAccessor { - static final Field swt_control_handle; - static final boolean swt_uses_long_handles; - + private static final boolean DEBUG = true; + + private static final Field swt_control_handle; + private static final boolean swt_uses_long_handles; + + private static Object swt_osx_init = new Object(); + private static Field swt_osx_control_view = null; + private static Field swt_osx_view_id = null; + + private static final String nwt; + public static final boolean isOSX; + public static final boolean isWindows; + public static final boolean isX11; + public static final boolean isX11GTK; + // X11/GTK, Windows/GDI, .. - static final String str_handle = "handle"; - + private static final String str_handle = "handle"; + // OSX/Cocoa - static final String str_view = "view"; // OSX - static final String str_id = "id"; // OSX + private static final String str_osx_view = "view"; // OSX + private static final String str_osx_id = "id"; // OSX // static final String str_NSView = "org.eclipse.swt.internal.cocoa.NSView"; - - static final Method swt_control_internal_new_GC; - static final Method swt_control_internal_dispose_GC; - static final String str_internal_new_GC = "internal_new_GC"; - static final String str_internal_dispose_GC = "internal_dispose_GC"; - - static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS"; - static final Class<?> OS_gtk_class; - static final Method OS_gtk_widget_realize; - static final Method OS_gtk_widget_unrealize; - static final Method OS_GTK_WIDGET_WINDOW; - static final Method OS_gdk_x11_drawable_get_xdisplay; - static final Method OS_gdk_x11_drawable_get_xid; - static final String str_gtk_widget_realize = "gtk_widget_realize"; - static final String str_gtk_widget_unrealize = "gtk_widget_unrealize"; - static final String str_GTK_WIDGET_WINDOW = "GTK_WIDGET_WINDOW"; - static final String str_gdk_x11_drawable_get_xdisplay = "gdk_x11_drawable_get_xdisplay"; - static final String str_gdk_x11_drawable_get_xid = "gdk_x11_drawable_get_xid"; - + + private static final Method swt_control_internal_new_GC; + private static final Method swt_control_internal_dispose_GC; + private static final String str_internal_new_GC = "internal_new_GC"; + private static final String str_internal_dispose_GC = "internal_dispose_GC"; + + private static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS"; + public static final Class<?> OS_gtk_class; + private static final String str_OS_gtk_version = "GTK_VERSION"; + public static final VersionNumber OS_gtk_version; + + private static final Method OS_gtk_widget_realize; + private static final Method OS_gtk_widget_unrealize; // optional (removed in SWT 4.3) + private static final Method OS_GTK_WIDGET_WINDOW; + private static final Method OS_gtk_widget_get_window; + private static final Method OS_gdk_x11_drawable_get_xdisplay; + private static final Method OS_gdk_x11_display_get_xdisplay; + private static final Method OS_gdk_window_get_display; + private static final Method OS_gdk_x11_drawable_get_xid; + private static final Method OS_gdk_x11_window_get_xid; + private static final Method OS_gdk_window_set_back_pixmap; + + private static final String str_gtk_widget_realize = "gtk_widget_realize"; + private static final String str_gtk_widget_unrealize = "gtk_widget_unrealize"; + private static final String str_GTK_WIDGET_WINDOW = "GTK_WIDGET_WINDOW"; + private static final String str_gtk_widget_get_window = "gtk_widget_get_window"; + private static final String str_gdk_x11_drawable_get_xdisplay = "gdk_x11_drawable_get_xdisplay"; + private static final String str_gdk_x11_display_get_xdisplay = "gdk_x11_display_get_xdisplay"; + private static final String str_gdk_window_get_display = "gdk_window_get_display"; + private static final String str_gdk_x11_drawable_get_xid = "gdk_x11_drawable_get_xid"; + private static final String str_gdk_x11_window_get_xid = "gdk_x11_window_get_xid"; + private static final String str_gdk_window_set_back_pixmap = "gdk_window_set_back_pixmap"; + + private static final VersionNumber GTK_VERSION_2_14_0 = new VersionNumber(2, 14, 0); + private static final VersionNumber GTK_VERSION_2_24_0 = new VersionNumber(2, 24, 0); + private static final VersionNumber GTK_VERSION_3_0_0 = new VersionNumber(3, 0, 0); + + private static VersionNumber GTK_VERSION(int version) { + // return (major << 16) + (minor << 8) + micro; + final int micro = ( version ) & 0x0f; + final int minor = ( version >> 8 ) & 0x0f; + final int major = ( version >> 16 ) & 0x0f; + return new VersionNumber(major, minor, micro); + } + static { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + NativeWindowFactory.initSingleton(); // last resort .. + return null; + } } ); + + nwt = NativeWindowFactory.getNativeWindowType(false); + isOSX = NativeWindowFactory.TYPE_MACOSX == nwt; + isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt; + isX11 = NativeWindowFactory.TYPE_X11 == nwt; + Field f = null; - - if(NativeWindowFactory.TYPE_MACOSX != NativeWindowFactory.getNativeWindowType(false) ) { + if( !isOSX ) { try { f = Control.class.getField(str_handle); } catch (Exception ex) { throw new NativeWindowException(ex); } - } + } swt_control_handle = f; // maybe null ! - + boolean ulh; if (null != swt_control_handle) { ulh = swt_control_handle.getGenericType().toString().equals(long.class.toString()); @@ -95,7 +152,7 @@ public class SWTAccessor { swt_uses_long_handles = ulh; // System.err.println("SWT long handles: " + swt_uses_long_handles); // System.err.println("Platform 64bit: "+Platform.is64Bit()); - + Method m=null; try { m = ReflectionUtil.getMethod(Control.class, str_internal_new_GC, new Class[] { GCData.class }); @@ -103,51 +160,88 @@ public class SWTAccessor { throw new NativeWindowException(ex); } swt_control_internal_new_GC = m; - + try { if(swt_uses_long_handles) { - m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { long.class, GCData.class }); + m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { long.class, GCData.class }); } else { - m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { int.class, GCData.class }); + m = Control.class.getDeclaredMethod(str_internal_dispose_GC, new Class[] { int.class, GCData.class }); } } catch (NoSuchMethodException ex) { throw new NativeWindowException(ex); } swt_control_internal_dispose_GC = m; - Class<?> c=null; - Method m1=null, m2=null, m3=null, m4=null, m5=null; - Class<?> handleType = swt_uses_long_handles ? long.class : int.class ; - if( NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(false) ) { + Class<?> c=null; + VersionNumber _gtk_version = new VersionNumber(0, 0, 0); + Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null, ma=null; + final Class<?> handleType = swt_uses_long_handles ? long.class : int.class ; + if( isX11 ) { + // mandatory try { c = ReflectionUtil.getClass(str_OS_gtk_class, false, SWTAccessor.class.getClassLoader()); - m1 = c.getDeclaredMethod(str_gtk_widget_realize, handleType); - m2 = c.getDeclaredMethod(str_gtk_widget_unrealize, handleType); - m3 = c.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType); - m4 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType); - m5 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType); + Field field_OS_gtk_version = c.getField(str_OS_gtk_version); + _gtk_version = GTK_VERSION(field_OS_gtk_version.getInt(null)); + m1 = c.getDeclaredMethod(str_gtk_widget_realize, handleType); + if (_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) { + m4 = c.getDeclaredMethod(str_gtk_widget_get_window, handleType); + } else { + m3 = c.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType); + } + if (_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) { + m6 = c.getDeclaredMethod(str_gdk_x11_display_get_xdisplay, handleType); + m7 = c.getDeclaredMethod(str_gdk_window_get_display, handleType); + } else { + m5 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType); + } + if (_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) { + m9 = c.getDeclaredMethod(str_gdk_x11_window_get_xid, handleType); + } else { + m8 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType); + } + ma = c.getDeclaredMethod(str_gdk_window_set_back_pixmap, handleType, handleType, boolean.class); } catch (Exception ex) { throw new NativeWindowException(ex); } + // optional + try { + m2 = c.getDeclaredMethod(str_gtk_widget_unrealize, handleType); + } catch (Exception ex) { } } OS_gtk_class = c; + OS_gtk_version = _gtk_version; OS_gtk_widget_realize = m1; OS_gtk_widget_unrealize = m2; OS_GTK_WIDGET_WINDOW = m3; - OS_gdk_x11_drawable_get_xdisplay = m4; - OS_gdk_x11_drawable_get_xid = m5; + OS_gtk_widget_get_window = m4; + OS_gdk_x11_drawable_get_xdisplay = m5; + OS_gdk_x11_display_get_xdisplay = m6; + OS_gdk_window_get_display = m7; + OS_gdk_x11_drawable_get_xid = m8; + OS_gdk_x11_window_get_xid = m9; + OS_gdk_window_set_back_pixmap = ma; + + isX11GTK = isX11 && null != OS_gtk_class; + + if(DEBUG) { + System.err.println("SWTAccessor.<init>: GTK Version: "+OS_gtk_version); + } } - static Object getIntOrLong(long arg) { + private static Number getIntOrLong(long arg) { if(swt_uses_long_handles) { return new Long(arg); } return new Integer((int) arg); } - - static void callStaticMethodL2V(Method m, long arg) { + + private static void callStaticMethodL2V(Method m, long arg) { ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); } - - static long callStaticMethodL2L(Method m, long arg) { + + private static void callStaticMethodLLZ2V(Method m, long arg0, long arg1, boolean arg3) { + ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1), Boolean.valueOf(arg3) }); + } + + private static long callStaticMethodL2L(Method m, long arg) { Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); if(o instanceof Number) { return ((Number)o).longValue(); @@ -155,82 +249,194 @@ public class SWTAccessor { throw new InternalError("SWT method "+m.getName()+" didn't return int or long but "+o.getClass()); } } - + + // + // Public properties + // + public static boolean isUsingLongHandles() { return swt_uses_long_handles; } - public static long getHandle(Control swtControl) { + public static boolean useX11GTK() { return isX11GTK; } + public static VersionNumber GTK_VERSION() { return OS_gtk_version; } + + // + // Common GTK + // + + public static long gdk_widget_get_window(long handle) { + final long window; + if (OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) { + window = callStaticMethodL2L(OS_gtk_widget_get_window, handle); + } else { + window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); + } + if(0 == window) { + throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle)); + } + return window; + } + + public static long gdk_window_get_xdisplay(long window) { + final long xdisplay; + if (OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) { + final long display = callStaticMethodL2L(OS_gdk_window_get_display, window); + if(0 == display) { + throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display); + } else { + xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window); + } + if(0 == xdisplay) { + throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + return xdisplay; + } + + public static long gdk_window_get_xwindow(long window) { + final long xWindow; + if (OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) { + xWindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window); + } else { + xWindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window); + } + if(0 == xWindow) { + throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + return xWindow; + } + + public static void gdk_window_set_back_pixmap(long window, long pixmap, boolean parent_relative) { + callStaticMethodLLZ2V(OS_gdk_window_set_back_pixmap, window, pixmap, parent_relative); + } + + // + // Common any toolkit + // + + /** + * @param swtControl the SWT Control to retrieve the native widget-handle from + * @return the native widget-handle + * @throws NativeWindowException if the widget handle is null + */ + public static long getHandle(Control swtControl) throws NativeWindowException { long h = 0; - if(NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false) ) { + if( isOSX ) { + synchronized(swt_osx_init) { + try { + if(null == swt_osx_view_id) { + swt_osx_control_view = Control.class.getField(str_osx_view); + Object view = swt_osx_control_view.get(swtControl); + swt_osx_view_id = view.getClass().getField(str_osx_id); + h = swt_osx_view_id.getLong(view); + } else { + h = swt_osx_view_id.getLong( swt_osx_control_view.get(swtControl) ); + } + } catch (Exception ex) { + throw new NativeWindowException(ex); + } + } + } else { try { - Field fView = Control.class.getField(str_view); - Object view = fView.get(swtControl); - Field fId = view.getClass().getField(str_id); - return fId.getLong(view); + h = swt_control_handle.getLong(swtControl); } catch (Exception ex) { throw new NativeWindowException(ex); - } + } } - - try { - h = swt_control_handle.getLong(swtControl); - } catch (Exception ex) { - throw new NativeWindowException(ex); + if(0 == h) { + throw new NativeWindowException("Null widget-handle of SWT "+swtControl.getClass().getName()+": "+swtControl.toString()); } return h; } - public static void setRealized(final Control swtControl, final boolean realize) { + public static void setRealized(final Control swtControl, final boolean realize) + throws NativeWindowException + { + if(!realize && swtControl.isDisposed()) { + return; + } final long handle = getHandle(swtControl); - + if(null != OS_gtk_class) { invoke(true, new Runnable() { + @Override public void run() { if(realize) { callStaticMethodL2V(OS_gtk_widget_realize, handle); - } else { + } else if(null != OS_gtk_widget_unrealize) { callStaticMethodL2V(OS_gtk_widget_unrealize, handle); - } + } } }); } } - - public static AbstractGraphicsDevice getDevice(Control swtControl) { - long handle = getHandle(swtControl); - if( null != OS_gtk_class ) { - long widgedHandle = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); - long displayHandle = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, widgedHandle); - // FIXME: May think about creating a private non-shared X11 Display handle, like we use to for AWT - // to avoid locking problems ! - return new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, false); + + /** + * @param swtControl the SWT Control to retrieve the native device handle from + * @return the AbstractGraphicsDevice w/ the native device handle + * @throws NativeWindowException if the widget handle is null + * @throws UnsupportedOperationException if the windowing system is not supported + */ + public static AbstractGraphicsDevice getDevice(Control swtControl) throws NativeWindowException, UnsupportedOperationException { + final long handle = getHandle(swtControl); + if( isX11GTK ) { + final long xdisplay0 = gdk_window_get_xdisplay( gdk_widget_get_window( handle ) ); + return new X11GraphicsDevice(xdisplay0, AbstractGraphicsDevice.DEFAULT_UNIT, false /* owner */); } - if( NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false) ) { + if( isWindows ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - if( NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false) ) { + if( isOSX ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } - throw new UnsupportedOperationException("n/a for this windowing system: "+NativeWindowFactory.getNativeWindowType(false)); + throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + } + + /** + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return + */ + public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) { + return NativeWindowFactory.createScreen(device, screen); } - - public static long getWindowHandle(Control swtControl) { - long handle = getHandle(swtControl); - if( null != OS_gtk_class ) { - long widgedHandle = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); - return callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, widgedHandle); + + public static int getNativeVisualID(AbstractGraphicsDevice device, long windowHandle) { + if( isX11 ) { + return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); } - if( NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false) || - NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false) ) { + if( isWindows || isOSX ) { + return VisualIDHolder.VID_UNDEFINED; + } + throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + } + + /** + * @param swtControl the SWT Control to retrieve the native window handle from + * @return the native window handle + * @throws NativeWindowException if the widget handle is null + * @throws UnsupportedOperationException if the windowing system is not supported + */ + public static long getWindowHandle(Control swtControl) throws NativeWindowException, UnsupportedOperationException { + final long handle = getHandle(swtControl); + if(0 == handle) { + throw new NativeWindowException("Null SWT handle of SWT control "+swtControl); + } + if( isX11GTK ) { + return gdk_window_get_xwindow( gdk_widget_get_window( handle ) ); + } + if( isWindows || isOSX ) { return handle; } - throw new UnsupportedOperationException("n/a for this windowing system: "+NativeWindowFactory.getNativeWindowType(false)); + throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } - + public static long newGC(final Control swtControl, final GCData gcData) { final Object[] o = new Object[1]; invoke(true, new Runnable() { + @Override public void run() { o[0] = ReflectionUtil.callMethod(swtControl, swt_control_internal_new_GC, new Object[] { gcData }); } @@ -244,6 +450,7 @@ public class SWTAccessor { public static void disposeGC(final Control swtControl, final long gc, final GCData gcData) { invoke(true, new Runnable() { + @Override public void run() { if(swt_uses_long_handles) { ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { new Long(gc), gcData }); @@ -253,13 +460,128 @@ public class SWTAccessor { } }); } - + + /** + * Runs the specified action in an SWT compatible thread, which is: + * <ul> + * <li>Mac OSX + * <ul> + * <!--li>AWT EDT: In case AWT is available, the AWT EDT is the OSX UI main thread</li--> + * <li><i>Main Thread</i>: Run on OSX UI main thread. 'wait' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread.</li> + * </ul></li> + * <li>Linux, Windows, .. + * <ul> + * <li>Current thread.</li> + * </ul></li> + * </ul> + * @see Platform#AWT_AVAILABLE + * @see Platform#getOSType() + */ public static void invoke(boolean wait, Runnable runnable) { - if(Platform.OS_TYPE == Platform.OSType.MACOS) { + if( isOSX ) { + // Use SWT main thread! Only reliable config w/ -XStartOnMainThread !? OSXUtil.RunOnMainThread(wait, runnable); } else { runnable.run(); - } + } + } + + /** + * Runs the specified action on the SWT UI thread. + * <p> + * If <code>display</code> is disposed or the current thread is the SWT UI thread + * {@link #invoke(boolean, Runnable)} is being used. + * @see #invoke(boolean, Runnable) + */ + public static void invoke(org.eclipse.swt.widgets.Display display, boolean wait, Runnable runnable) { + if( display.isDisposed() || Thread.currentThread() == display.getThread() ) { + invoke(wait, runnable); + } else if( wait ) { + display.syncExec(runnable); + } else { + display.asyncExec(runnable); + } + } + + // + // Specific X11 GTK ChildWindow - Using plain X11 native parenting (works well) + // + + public static long createCompatibleX11ChildWindow(AbstractGraphicsScreen screen, Control swtControl, int visualID, int width, int height) { + final long handle = getHandle(swtControl); + final long parentWindow = gdk_widget_get_window( handle ); + gdk_window_set_back_pixmap (parentWindow, 0, false); + + final long x11ParentHandle = gdk_window_get_xwindow(parentWindow); + final long x11WindowHandle = X11Lib.CreateWindow(x11ParentHandle, screen.getDevice().getHandle(), screen.getIndex(), visualID, width, height, true, true); + + return x11WindowHandle; + } + + public static void resizeX11Window(AbstractGraphicsDevice device, Rectangle clientArea, long x11Window) { + X11Lib.SetWindowPosSize(device.getHandle(), x11Window, clientArea.x, clientArea.y, clientArea.width, clientArea.height); + } + public static void destroyX11Window(AbstractGraphicsDevice device, long x11Window) { + X11Lib.DestroyWindow(device.getHandle(), x11Window); + } + + // + // Specific X11 SWT/GTK ChildWindow - Using SWT/GTK native parenting (buggy - sporadic resize flickering, sporadic drop of rendering) + // + // FIXME: Need to use reflection for 32bit access as well ! + // + + // public static final int GDK_WA_TYPE_HINT = 1 << 9; + // public static final int GDK_WA_VISUAL = 1 << 6; + + public static long createCompatibleGDKChildWindow(Control swtControl, int visualID, int width, int height) { + return 0; + /** + final long handle = SWTAccessor.getHandle(swtControl); + final long parentWindow = gdk_widget_get_window( handle ); + + final long screen = OS.gdk_screen_get_default (); + final long gdkvisual = OS.gdk_x11_screen_lookup_visual (screen, visualID); + + final GdkWindowAttr attrs = new GdkWindowAttr(); + attrs.width = width > 0 ? width : 1; + attrs.height = height > 0 ? height : 1; + attrs.event_mask = OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK | + OS.GDK_FOCUS_CHANGE_MASK | OS.GDK_POINTER_MOTION_MASK | + OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK | + OS.GDK_ENTER_NOTIFY_MASK | OS.GDK_LEAVE_NOTIFY_MASK | + OS.GDK_EXPOSURE_MASK | OS.GDK_VISIBILITY_NOTIFY_MASK | + OS.GDK_POINTER_MOTION_HINT_MASK; + attrs.window_type = OS.GDK_WINDOW_CHILD; + attrs.visual = gdkvisual; + + final long childWindow = OS.gdk_window_new (parentWindow, attrs, OS.GDK_WA_VISUAL|GDK_WA_TYPE_HINT); + OS.gdk_window_set_user_data (childWindow, handle); + OS.gdk_window_set_back_pixmap (parentWindow, 0, false); + + OS.gdk_window_show (childWindow); + OS.gdk_flush(); + return childWindow; */ + } + + public static void showGDKWindow(long gdkWindow) { + /* OS.gdk_window_show (gdkWindow); + OS.gdk_flush(); */ + } + public static void focusGDKWindow(long gdkWindow) { + /* + OS.gdk_window_show (gdkWindow); + OS.gdk_window_focus(gdkWindow, 0); + OS.gdk_flush(); */ + } + public static void resizeGDKWindow(Rectangle clientArea, long gdkWindow) { + /** + OS.gdk_window_move (gdkWindow, clientArea.x, clientArea.y); + OS.gdk_window_resize (gdkWindow, clientArea.width, clientArea.height); + OS.gdk_flush(); */ + } + + public static void destroyGDKWindow(long gdkWindow) { + // OS.gdk_window_destroy (gdkWindow); } - } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/windows/WindowsGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/windows/WindowsGraphicsDevice.java index 5cabdf150..643982715 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/windows/WindowsGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/windows/WindowsGraphicsDevice.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -34,7 +34,7 @@ package com.jogamp.nativewindow.windows; import javax.media.nativewindow.*; -/** +/** * Encapsulates a graphics device on Windows platforms.<br> */ public class WindowsGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { @@ -47,6 +47,7 @@ public class WindowsGraphicsDevice extends DefaultGraphicsDevice implements Clon super(NativeWindowFactory.TYPE_WINDOWS, connection, unitID); } + @Override public Object clone() { return super.clone(); } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java index 0d2914c7d..120c86584 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsConfiguration.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -48,7 +48,7 @@ import jogamp.nativewindow.x11.XVisualInfo; public class X11GraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { private XVisualInfo info; - public X11GraphicsConfiguration(X11GraphicsScreen screen, + public X11GraphicsConfiguration(X11GraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, XVisualInfo info) { super(screen, capsChosen, capsRequested); @@ -71,12 +71,12 @@ public class X11GraphicsConfiguration extends MutableGraphicsConfiguration imple final public int getXVisualID() { return (null!=info)?(int)info.getVisualid():0; } - + @Override public String toString() { return getClass().getSimpleName()+"["+getScreen()+", visualID 0x" + Long.toHexString(getXVisualID()) + ",\n\tchosen " + capabilitiesChosen+ - ",\n\trequested " + capabilitiesRequested+ + ",\n\trequested " + capabilitiesRequested+ "]"; } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java index 308756b54..863e53bde 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsDevice.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -33,7 +33,6 @@ package com.jogamp.nativewindow.x11; -import jogamp.nativewindow.Debug; import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; @@ -46,8 +45,8 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - public static final boolean DEBUG = Debug.debug("GraphicsDevice"); - final boolean closeDisplay; + /* final */ boolean handleOwner; + final boolean isXineramaEnabled; /** Constructs a new X11GraphicsDevice corresponding to the given connection and default * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#getDefaultToolkitLock(String)}.<br> @@ -57,25 +56,21 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl */ public X11GraphicsDevice(String connection, int unitID) { super(NativeWindowFactory.TYPE_X11, connection, unitID); - closeDisplay = false; + handleOwner = false; + isXineramaEnabled = false; } /** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default - * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long) */ public X11GraphicsDevice(long display, int unitID, boolean owner) { - // FIXME: derive unitID from connection could be buggy, one DISPLAY for all screens for example.. - super(NativeWindowFactory.TYPE_X11, X11Lib.XDisplayString(display), unitID, display); - if(0==display) { - throw new NativeWindowException("null display"); - } - closeDisplay = owner; + this(display, unitID, NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_X11, display), owner); } /** * @param display the Display connection - * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking in NEWT + * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking w/ private connection * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long, ToolkitLock) */ public X11GraphicsDevice(long display, int unitID, ToolkitLock locker, boolean owner) { @@ -83,16 +78,83 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl if(0==display) { throw new NativeWindowException("null display"); } - closeDisplay = owner; + handleOwner = owner; + isXineramaEnabled = X11Util.XineramaIsEnabled(this); + } + + /** + * Constructs a new X11GraphicsDevice corresponding to the given display connection. + * <p> + * The constructor opens the native connection and takes ownership. + * </p> + * @param displayConnection the semantic display connection name + * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking w/ private connection + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long, ToolkitLock) + */ + public X11GraphicsDevice(String displayConnection, int unitID, ToolkitLock locker) { + super(NativeWindowFactory.TYPE_X11, displayConnection, unitID, 0, locker); + handleOwner = true; + open(); + isXineramaEnabled = X11Util.XineramaIsEnabled(this); + } + + private static int getDefaultScreenImpl(long dpy) { + return X11Lib.DefaultScreen(dpy); } + /** + * Returns the default screen number as referenced by the display connection, i.e. 'somewhere:0.1' -> 1 + * <p> + * Implementation uses the XLib macro <code>DefaultScreen(display)</code>. + * </p> + */ + public int getDefaultScreen() { + final long display = getHandle(); + if(0==display) { + throw new NativeWindowException("null display"); + } + final int ds = getDefaultScreenImpl(display); + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.getDefaultDisplay() of "+this+": "+ds+", count "+X11Lib.ScreenCount(display)); + } + return ds; + } + + public int getDefaultVisualID() { + final long display = getHandle(); + if(0==display) { + throw new NativeWindowException("null display"); + } + return X11Lib.DefaultVisualID(display, getDefaultScreenImpl(display)); + } + + public final boolean isXineramaEnabled() { + return isXineramaEnabled; + } + + @Override public Object clone() { return super.clone(); } + @Override + public boolean open() { + if(handleOwner && 0 == handle) { + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.open(): "+this); + } + handle = X11Util.openDisplay(connection); + if(0 == handle) { + throw new NativeWindowException("X11GraphicsDevice.open() failed: "+this); + } + return true; + } + return false; + } + + @Override public boolean close() { - // FIXME: shall we respect the unitID ? - if(closeDisplay && 0 != handle) { + if(handleOwner && 0 != handle) { if(DEBUG) { System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.close(): "+this); } @@ -100,5 +162,23 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } return super.close(); } -} + @Override + public boolean isHandleOwner() { + return handleOwner; + } + @Override + public void clearHandleOwner() { + handleOwner = false; + } + @Override + protected Object getHandleOwnership() { + return Boolean.valueOf(handleOwner); + } + @Override + protected Object setHandleOwnership(Object newOwnership) { + final Boolean oldOwnership = Boolean.valueOf(handleOwner); + handleOwner = ((Boolean) newOwnership).booleanValue(); + return oldOwnership; + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java index 94013ec38..700937829 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/x11/X11GraphicsScreen.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution 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. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -33,10 +33,12 @@ package com.jogamp.nativewindow.x11; -import javax.media.nativewindow.*; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.DefaultGraphicsScreen; +import javax.media.nativewindow.NativeWindowException; import jogamp.nativewindow.x11.X11Lib; -import jogamp.nativewindow.x11.X11Util; /** Encapsulates a screen index on X11 platforms. Objects of this type are passed to {@link @@ -48,7 +50,7 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl /** Constructs a new X11GraphicsScreen corresponding to the given native screen index. */ public X11GraphicsScreen(X11GraphicsDevice device, int screen) { - super(device, fetchScreen(device, screen)); + super(device, device.isXineramaEnabled() ? 0 : screen); } public static AbstractGraphicsScreen createScreenDevice(long display, int screenIdx, boolean owner) { @@ -56,21 +58,12 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl return new X11GraphicsScreen(new X11GraphicsDevice(display, AbstractGraphicsDevice.DEFAULT_UNIT, owner), screenIdx); } - public long getDefaultVisualID() { + public int getVisualID() { // It still could be an AWT hold handle .. - long display = getDevice().getHandle(); - int scrnIdx = X11Lib.DefaultScreen(display); - return X11Lib.DefaultVisualID(display, scrnIdx); - } - - private static int fetchScreen(X11GraphicsDevice device, int screen) { - // It still could be an AWT hold handle .. - if(X11Util.XineramaIsEnabled(device.getHandle())) { - screen = 0; // Xinerama -> 1 screen - } - return screen; + return X11Lib.DefaultVisualID(getDevice().getHandle(), getIndex()); } + @Override public Object clone() { return super.clone(); } |