diff options
Diffstat (limited to 'src/nativewindow/classes/com')
21 files changed, 1929 insertions, 493 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java index 22c95f3dd..e785af788 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java @@ -11,29 +11,29 @@ public class DelegatedUpstreamSurfaceHookMutableSize extends UpstreamSurfaceHook * @param width initial width * @param height initial height */ - public DelegatedUpstreamSurfaceHookMutableSize(UpstreamSurfaceHook upstream, int width, int height) { + public DelegatedUpstreamSurfaceHookMutableSize(final UpstreamSurfaceHook upstream, final int width, final int height) { super(width, height); this.upstream = upstream; } @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { if(null != upstream) { upstream.create(s); } } @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { if(null != upstream) { upstream.destroy(s); } } - + @Override public String toString() { - return getClass().getSimpleName()+"[ "+ width + "x" + height + ", " + upstream + "]"; + return getClass().getSimpleName()+"[ "+ pixWidth + "x" + pixHeight + ", " + upstream + "]"; } - + } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java index 85e24582c..abcc166cb 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java @@ -10,9 +10,9 @@ public class DelegatedUpstreamSurfaceHookWithSurfaceSize implements UpstreamSurf /** * @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)} + * @param surface mandatory {@link NativeSurface} used for {@link #getSurfaceWidth(ProxySurface)} and {@link #getSurfaceHeight(ProxySurface)}, not used for {@link #getUpstreamSurface()}. */ - public DelegatedUpstreamSurfaceHookWithSurfaceSize(UpstreamSurfaceHook upstream, NativeSurface surface) { + public DelegatedUpstreamSurfaceHookWithSurfaceSize(final UpstreamSurfaceHook upstream, final NativeSurface surface) { this.upstream = upstream; this.surface = surface; if(null == surface) { @@ -20,35 +20,46 @@ public class DelegatedUpstreamSurfaceHookWithSurfaceSize implements UpstreamSurf } } + /** + * {@inheritDoc} + * <p> + * Returns <code>null</code>. + * </p> + */ + @Override + public final NativeSurface getUpstreamSurface() { + return null; + } + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { if(null != upstream) { upstream.create(s); } } @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { if(null != upstream) { upstream.destroy(s); } } @Override - public final int getWidth(ProxySurface s) { - return surface.getWidth(); + public final int getSurfaceWidth(final ProxySurface s) { + return surface.getSurfaceWidth(); } @Override - public final int getHeight(ProxySurface s) { - return surface.getHeight(); - } - + public final int getSurfaceHeight(final ProxySurface s) { + return surface.getSurfaceHeight(); + } + @Override public String toString() { - final String us_s = null != surface ? ( surface.getClass().getName() + ": 0x" + Long.toHexString(surface.getSurfaceHandle()) + " " +surface.getWidth() + "x" + surface.getHeight() ) : "nil"; + final String us_s = null != surface ? ( surface.getClass().getName() + ": 0x" + Long.toHexString(surface.getSurfaceHandle()) + " " +surface.getSurfaceWidth() + "x" + surface.getSurfaceHeight() ) : "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..a137d46c3 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/MutableGraphicsConfiguration.java @@ -32,12 +32,19 @@ import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.DefaultGraphicsConfiguration; public class MutableGraphicsConfiguration extends DefaultGraphicsConfiguration { - public MutableGraphicsConfiguration(AbstractGraphicsScreen screen, - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + public MutableGraphicsConfiguration(final AbstractGraphicsScreen screen, + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested) { super(screen, capsChosen, capsRequested); } - public void setChosenCapabilities(CapabilitiesImmutable caps) { + @Override + public void setChosenCapabilities(final CapabilitiesImmutable caps) { super.setChosenCapabilities(caps); } + + @Override + public void setScreen(final 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..7c1a88e6a 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,24 +20,25 @@ * 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 { protected static volatile NativeWindowVersion jogampCommonVersionInfo; - protected NativeWindowVersion(String packageName, Manifest mf) { + protected NativeWindowVersion(final String packageName, final Manifest mf) { super(packageName, mf); } @@ -45,16 +46,17 @@ 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); } } } return jogampCommonVersionInfo; } - public static void main(String args[]) { + public static void main(final String args[]) { System.err.println(VersionUtil.getPlatformInfo()); System.err.println(GlueGenVersion.getInstance()); System.err.println(NativeWindowVersion.getInstance()); diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java index 29c540ac4..45d12be5e 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java @@ -1,45 +1,57 @@ package com.jogamp.nativewindow; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.UpstreamSurfaceHook; public class UpstreamSurfaceHookMutableSize implements UpstreamSurfaceHook.MutableSize { - int width, height; + int pixWidth, pixHeight; /** * @param width initial width * @param height initial height */ - public UpstreamSurfaceHookMutableSize(int width, int height) { - this.width = width; - this.height = height; + public UpstreamSurfaceHookMutableSize(final int width, final int height) { + this.pixWidth = width; + this.pixHeight = height; } @Override - public final void setSize(int width, int height) { - this.width = width; - this.height = height; + public final void setSurfaceSize(final int width, final int height) { + this.pixWidth = width; + this.pixHeight = height; } - + @Override - public final int getWidth(ProxySurface s) { - return width; + public final int getSurfaceWidth(final ProxySurface s) { + return pixWidth; } @Override - public final int getHeight(ProxySurface s) { - return height; + public final int getSurfaceHeight(final ProxySurface s) { + return pixHeight; } @Override - public void create(ProxySurface s) { /* nop */ } + public void create(final ProxySurface s) { /* nop */ } @Override - public void destroy(ProxySurface s) { /* nop */ } - + public void destroy(final ProxySurface s) { /* nop */ } + @Override public String toString() { - return getClass().getSimpleName()+"[ "+ width + "x" + height + "]"; + return getClass().getSimpleName()+"[pixel "+ pixWidth + "x" + pixHeight + "]"; + } + + /** + * {@inheritDoc} + * <p> + * Returns <code>null</code>. + * </p> + */ + @Override + public final NativeSurface getUpstreamSurface() { + return null; } - + } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamWindowHookMutableSizePos.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamWindowHookMutableSizePos.java new file mode 100644 index 000000000..b509f118a --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamWindowHookMutableSizePos.java @@ -0,0 +1,56 @@ +package com.jogamp.nativewindow; + +public class UpstreamWindowHookMutableSizePos extends UpstreamSurfaceHookMutableSize { + int winX, winY, winWidth, winHeight; + + /** + * @param winX initial window x-pos + * @param winY initial window y-pos + * @param winWidth initial window width + * @param winHeight initial window height + * @param pixWidth initial surface pixel width, FIXME: pixel-dim == window-dim 'for now' ? + * @param pixHeight initial surface pixel height, FIXME: pixel-dim == window-dim 'for now' ? + */ + public UpstreamWindowHookMutableSizePos(final int winX, final int winY, final int winWidth, final int winHeight, final int pixWidth, final int pixHeight) { + super(pixWidth, pixHeight); + this.winX= winX; + this.winY= winY; + this.winWidth = winWidth; + this.winHeight = winHeight; + } + + // @Override + public final void setWinPos(final int winX, final int winY) { + this.winX= winX; + this.winY= winY; + } + // @Override + public final void setWinSize(final int winWidth, final int winHeight) { + this.winWidth= winWidth; + this.winHeight= winHeight; + // FIXME HiDPI: Use pixelScale ?! + // FIXME HiDPI: Consider setting winWidth/winHeight by setSurfaceSize(..) (back-propagation) + this.setSurfaceSize(winWidth, winHeight); + } + + public final int getX() { + return winX; + } + + public final int getY() { + return winY; + } + public final int getWidth() { + return winWidth; + } + public final int getHeight() { + return winHeight; + } + + @Override + public String toString() { + return getClass().getSimpleName()+"[window "+ winX + "/" + winY + " " + winWidth + "x" + winHeight + ", pixel " + pixWidth + "x" + pixHeight + "]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsConfiguration.java index 2a152ff35..3a62825a2 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. */ @@ -54,33 +54,34 @@ import jogamp.nativewindow.Debug; handled in a toolkit-independent manner. */ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { - private GraphicsConfiguration config; + private final GraphicsConfiguration config; AbstractGraphicsConfiguration encapsulated; - public AWTGraphicsConfiguration(AWTGraphicsScreen screen, - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - GraphicsConfiguration config, AbstractGraphicsConfiguration encapsulated) { + public AWTGraphicsConfiguration(final AWTGraphicsScreen screen, + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final GraphicsConfiguration config, final AbstractGraphicsConfiguration encapsulated) { super(screen, capsChosen, capsRequested); this.config = config; this.encapsulated=encapsulated; } - private AWTGraphicsConfiguration(AWTGraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - GraphicsConfiguration config) { + private AWTGraphicsConfiguration(final AWTGraphicsScreen screen, final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final GraphicsConfiguration config) { super(screen, capsChosen, capsRequested); 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) { + public static AWTGraphicsConfiguration create(final Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { final GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration(); if(null==awtGfxConfig) { - throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp); + throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp); } final GraphicsDevice awtGraphicsDevice = awtGfxConfig.getDevice(); if(null==awtGraphicsDevice) { @@ -91,8 +92,11 @@ 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(); + final GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsRequested, gc); } final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice, capsChosen); @@ -105,10 +109,11 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple } // open access to superclass method - public void setChosenCapabilities(CapabilitiesImmutable capsChosen) { + @Override + public void setChosenCapabilities(final CapabilitiesImmutable capsChosen) { super.setChosenCapabilities(capsChosen); } - + @Override public Object clone() { return super.clone(); @@ -131,16 +136,16 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple * @param gc the GraphicsConfiguration from which to derive the RGBA bit depths * @return the passed Capabilities */ - public static CapabilitiesImmutable setupCapabilitiesRGBABits(CapabilitiesImmutable capabilitiesIn, GraphicsConfiguration gc) { - Capabilities capabilities = (Capabilities) capabilitiesIn.cloneMutable(); + public static CapabilitiesImmutable setupCapabilitiesRGBABits(final CapabilitiesImmutable capabilitiesIn, final GraphicsConfiguration gc) { + final Capabilities capabilities = (Capabilities) capabilitiesIn.cloneMutable(); - ColorModel cm = gc.getColorModel(); + final ColorModel cm = gc.getColorModel(); if(null==cm) { throw new NativeWindowException("Could not determine AWT ColorModel"); } - int cmBitsPerPixel = cm.getPixelSize(); + final int cmBitsPerPixel = cm.getPixelSize(); int bitsPerPixel = 0; - int[] bitesPerComponent = cm.getComponentSize(); + final int[] bitesPerComponent = cm.getComponentSize(); if(bitesPerComponent.length>=3) { capabilities.setRedBits(bitesPerComponent[0]); bitsPerPixel += bitesPerComponent[0]; @@ -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..219f4bb92 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. */ @@ -48,15 +48,15 @@ import javax.media.nativewindow.AbstractGraphicsDevice; /** A wrapper for an AWT GraphicsDevice allowing it to be handled in a toolkit-independent manner. */ public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - private GraphicsDevice device; + private final GraphicsDevice device; - public AWTGraphicsDevice(GraphicsDevice device, int unitID) { + public AWTGraphicsDevice(final GraphicsDevice device, final int unitID) { super(NativeWindowFactory.TYPE_AWT, device.getIDstring(), unitID); this.device = device; } public static AWTGraphicsDevice createDefault() { - GraphicsDevice awtDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + final GraphicsDevice awtDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); return new AWTGraphicsDevice(awtDevice, AbstractGraphicsDevice.DEFAULT_UNIT); } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTGraphicsScreen.java index f4ee06e28..6fc35f719 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. */ @@ -51,35 +51,35 @@ import javax.media.nativewindow.*; public class AWTGraphicsScreen extends DefaultGraphicsScreen implements Cloneable { - public AWTGraphicsScreen(AWTGraphicsDevice device) { + public AWTGraphicsScreen(final AWTGraphicsDevice device) { super(device, findScreenIndex(device.getGraphicsDevice())); } - public static GraphicsDevice getScreenDevice(int index) { + public static GraphicsDevice getScreenDevice(final int index) { if(index<0) return null; - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] gs = ge.getScreenDevices(); + final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + final GraphicsDevice[] gs = ge.getScreenDevices(); if(index<gs.length) { return gs[index]; } return null; } - public static int findScreenIndex(GraphicsDevice awtDevice) { + public static int findScreenIndex(final GraphicsDevice awtDevice) { if(null==awtDevice) return -1; - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] gs = ge.getScreenDevices(); + final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + final GraphicsDevice[] gs = ge.getScreenDevices(); for (int j = 0; j < gs.length; j++) { if(gs[j] == awtDevice) return j; } return -1; } - public static AbstractGraphicsScreen createScreenDevice(GraphicsDevice awtDevice, int unitID) { + public static AbstractGraphicsScreen createScreenDevice(final GraphicsDevice awtDevice, final int unitID) { return new AWTGraphicsScreen(new AWTGraphicsDevice(awtDevice, unitID)); } - public static AbstractGraphicsScreen createScreenDevice(int index, int unitID) { + public static AbstractGraphicsScreen createScreenDevice(final int index, final int unitID) { return createScreenDevice(getScreenDevice(index), unitID); } @@ -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..b0a7fbc76 --- /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(final Container c, final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final 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(final Component c) { + ((AWTPrintLifecycle)c).setupPrint(scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight); + } }; + private final AWTMisc.ComponentAction releaseAction = new AWTMisc.ComponentAction() { + @Override + public void run(final Component c) { + ((AWTPrintLifecycle)c).releasePrint(); + } }; + + private Context(final Container c, final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final 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(final 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..496e6e07b 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTWindowClosingProtocol.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AWTWindowClosingProtocol.java @@ -33,80 +33,81 @@ 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(final Component comp, final Runnable closingOperationClose, final Runnable closingOperationNOP) { this.comp = comp; - this.closingOperation = closingOperation; + this.listenTo = null; + this.closingOperationClose = closingOperationClose; + this.closingOperationNOP = closingOperationNOP; } class WindowClosingAdapter extends WindowAdapter { @Override - public void windowClosing(WindowEvent e) { + public void windowClosing(final WindowEvent e) { final WindowClosingMode op = AWTWindowClosingProtocol.this.getDefaultCloseOperation(); 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,7 +127,8 @@ public class AWTWindowClosingProtocol implements WindowClosingProtocol { return AWTMisc.getNWClosingOperation(comp); } - public final WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) { + @Override + public final WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) { synchronized(closingListenerLock) { final WindowClosingMode _op = defaultCloseOperation; defaultCloseOperation = op; diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java new file mode 100644 index 000000000..2026ada0f --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/AppContextInfo.java @@ -0,0 +1,199 @@ +package com.jogamp.nativewindow.awt; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import com.jogamp.common.util.RunnableTask; + +import jogamp.nativewindow.jawt.JAWTUtil; + +/** + * Instance of this class holds information about a {@link ThreadGroup} associated {@link sun.awt.AppContext}. + * <p> + * Non intrusive workaround for Bug 983 and Bug 1004, see {@link #getCachedThreadGroup()}. + * </p> + */ +public class AppContextInfo { + private static final boolean DEBUG; + + private static final Method getAppContextMethod; + private static final Object mainThreadAppContextLock = new Object(); + private volatile WeakReference<Object> mainThreadAppContextWR = null; + private volatile WeakReference<ThreadGroup> mainThreadGroupWR = null; + + static { + DEBUG = JAWTUtil.DEBUG; + final Method[] _getAppContextMethod = { null }; + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + try { + final Class<?> appContextClass = Class.forName("sun.awt.AppContext"); + _getAppContextMethod[0] = appContextClass.getMethod("getAppContext"); + } catch(final Throwable ex) { + System.err.println("Bug 1004: Caught @ static: "+ex.getMessage()); + ex.printStackTrace(); + } + return null; + } } ); + getAppContextMethod = _getAppContextMethod[0]; + } + + public AppContextInfo(final String info) { + update(info); + } + + /** + * Returns <code>true</code> if this instance has valid {@link sun.awt.AppContext} information, + * i.e. {@link #getCachedThreadGroup()} returns not <code>null</code>. + */ + public final boolean isValid() { + return null != getCachedThreadGroup(); + } + + /** + * Returns the {@link ThreadGroup} belonging to the + * last known {@link sun.awt.AppContext} as queried via {@link #update(String)}. + * <p> + * Returns <code>null</code> if no {@link sun.awt.AppContext} has been queried. + * </p> + * <p> + * The returned {@link ThreadGroup} allows users to create a custom thread + * belonging to it and hence mitigating Bug 983 and Bug 1004. + * </p> + * <p> + * {@link #update(String)} should be called from a thread belonging to the + * desired {@link sun.awt.AppContext}, i.e. early from within the special threaded application. + * </p> + * <p> + * E.g. {@link JAWTWindow} issues {@link #update(String)} in it's constructor. + * </p> + */ + public final ThreadGroup getCachedThreadGroup() { + final WeakReference<ThreadGroup> tgRef = mainThreadGroupWR; + return null != tgRef ? tgRef.get() : null; + } + + /** + * Invokes <code>runnable</code> on a {@link Thread} belonging to the {@link sun.awt.AppContext} {@link ThreadGroup}, + * see {@link #getCachedThreadGroup()}. + * <p> + * {@link #update(String)} is issued first, which returns <code>true</code> + * if the current thread belongs to an AppContext {@link ThreadGroup}. + * In this case the <code>runnable</code> is invoked on the current thread, + * otherwise a new {@link Thread} will be started. + * </p> + * <p> + * If a new {@link Thread} is required, the AppContext {@link ThreadGroup} is being used + * if {@link #isValid() available}, otherwise the default system {@link ThreadGroup}. + * </p> + * + * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately. + * @param runnable the {@link Runnable} to be executed. If <code>waitUntilDone</code> is <code>true</code>, + * the runnable <b>must exist</b>, i.e. not loop forever. + * @param threadBaseName the base name for the new thread if required. + * The resulting thread name will have either '-OnAppContextTG' or '-OnSystemTG' appended + * @return the {@link Thread} used to invoke the <code>runnable</code>, which may be the current {@link Thread} or a newly created one, see above. + */ + public Thread invokeOnAppContextThread(final boolean waitUntilDone, final Runnable runnable, final String threadBaseName) { + final Thread t; + if( update("invoke") ) { + t = Thread.currentThread(); + if( DEBUG ) { + System.err.println("Bug 1004: Invoke.0 on current AppContext thread: "+t+" "+toHexString(t.hashCode())); + } + runnable.run(); + } else { + final ThreadGroup tg = getCachedThreadGroup(); + final String tName = threadBaseName + ( null != tg ? "-OnAppContextTG" : "-OnSystemTG" ); + t = RunnableTask.invokeOnNewThread(tg, waitUntilDone, runnable, tName); + if( DEBUG ) { + final int tgHash = null != tg ? tg.hashCode() : 0; + System.err.println("Bug 1004: Invoke.1 on new AppContext thread: "+t+" "+toHexString(t.hashCode())+", tg "+tg+" "+toHexString(tgHash)); + } + } + return t; + } + + /** + * Update {@link sun.awt.AppContext} information for the current ThreadGroup if uninitialized or {@link sun.awt.AppContext} changed. + * <p> + * See {@link #getCachedThreadGroup()} for usage. + * </p> + * @param info informal string for logging purposes + * @return <code>true</code> if the current ThreadGroup is mapped to an {@link sun.awt.AppContext} and the information is good, otherwise false. + */ + public final boolean update(final String info) { + if ( null != getAppContextMethod ) { + // Test whether the current thread's ThreadGroup is mapped to an AppContext. + final Object thisThreadAppContext = fetchAppContext(); + final boolean tgMapped = null != thisThreadAppContext; + + final Thread thread = Thread.currentThread(); + final ThreadGroup threadGroup = thread.getThreadGroup(); + final Object mainThreadAppContext; + { + final WeakReference<Object> _mainThreadAppContextWR = mainThreadAppContextWR; + mainThreadAppContext = null != _mainThreadAppContextWR ? _mainThreadAppContextWR.get() : null; + } + + if( tgMapped ) { // null != thisThreadAppContext + // Update info is possible + if( null == mainThreadAppContext || + mainThreadAppContext != thisThreadAppContext ) { + // GC'ed or 1st fetch ! + final int mainThreadAppContextHash = null != mainThreadAppContext ? mainThreadAppContext.hashCode() : 0; + final int thisThreadAppContextHash; + synchronized(mainThreadAppContextLock) { + mainThreadGroupWR = new WeakReference<ThreadGroup>(threadGroup); + mainThreadAppContextWR = new WeakReference<Object>(thisThreadAppContext); + thisThreadAppContextHash = thisThreadAppContext.hashCode(); + } + if( DEBUG ) { + System.err.println("Bug 1004[TGMapped "+tgMapped+"]: Init AppContext @ "+info+" on thread "+thread.getName()+" "+toHexString(thread.hashCode())+ + ": tg "+threadGroup.getName()+" "+toHexString(threadGroup.hashCode())+ + " -> appCtx [ main "+mainThreadAppContext+" "+toHexString(mainThreadAppContextHash)+ + " -> this "+thisThreadAppContext+" "+toHexString(thisThreadAppContextHash) + " ] "); + } + } else { + // old info is OK + if( DEBUG ) { + final int mainThreadAppContextHash = mainThreadAppContext.hashCode(); + final int thisThreadAppContextHash = thisThreadAppContext.hashCode(); + System.err.println("Bug 1004[TGMapped "+tgMapped+"]: OK AppContext @ "+info+" on thread "+thread.getName()+" "+toHexString(thread.hashCode())+ + ": tg "+threadGroup.getName()+" "+toHexString(threadGroup.hashCode())+ + " : appCtx [ this "+thisThreadAppContext+" "+toHexString(thisThreadAppContextHash)+ + " , main "+mainThreadAppContext+" "+toHexString(mainThreadAppContextHash) + " ] "); + } + } + return true; + } else { + if( DEBUG ) { + final int mainThreadAppContextHash = null != mainThreadAppContext ? mainThreadAppContext.hashCode() : 0; + final int thisThreadAppContextHash = null != thisThreadAppContext ? thisThreadAppContext.hashCode() : 0; + System.err.println("Bug 1004[TGMapped "+tgMapped+"]: No AppContext @ "+info+" on thread "+thread.getName()+" "+toHexString(thread.hashCode())+ + ": tg "+threadGroup.getName()+" "+toHexString(threadGroup.hashCode())+ + " -> appCtx [ this "+thisThreadAppContext+" "+toHexString(thisThreadAppContextHash)+ + " -> main "+mainThreadAppContext+" "+toHexString(mainThreadAppContextHash) + " ] "); + } + } + } + return false; + } + private static Object fetchAppContext() { + try { + return getAppContextMethod.invoke(null); + } catch(final Exception ex) { + System.err.println("Bug 1004: Caught: "+ex.getMessage()); + ex.printStackTrace(); + return null; + } + } + + private static String toHexString(final int i) { + return "0x"+Integer.toHexString(i); + } + +} 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..c7055099f --- /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(final SampleModel sampleModel, final DirectDataBufferInt dataBuffer, final Point origin) { + super(sampleModel, dataBuffer, origin); + } + } + + public static class BufferedImageInt extends BufferedImage { + final int customImageType; + public BufferedImageInt (final int customImageType, final ColorModel cm, final WritableRaster raster, final 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(final int width, final int height, final int imageType, Point location, final 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 final IntBuffer data; + + /** All data banks */ + private final 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(final 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(final int size, final 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(final IntBuffer dataArray, final 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(final 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(final 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(final int bank, final 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(final int i, final 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(final int bank, final int i, final 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 a62d08ccf..6498ebd1e 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -37,13 +37,22 @@ 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; @@ -52,29 +61,37 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.OffscreenLayerOption; import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.ScalableSurface; 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.common.os.PlatformPropsImpl; +import jogamp.nativewindow.SurfaceScaleUtils; 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; -public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption { +public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption, ScalableSurface { protected static final boolean DEBUG = JAWTUtil.DEBUG; // 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 AppContextInfo appContextInfo; + private final AWTGraphicsConfiguration config; // control access due to delegation + private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); + private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private final JAWTComponentListener jawtComponentListener; // lifetime: valid after lock but may change with each 1st lock, purges after invalidate private boolean isApplet; @@ -83,7 +100,11 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, protected long drawable; protected Rectangle bounds; protected Insets insets; - private long offscreenSurfaceLayer; + private volatile long offscreenSurfaceLayer; + + private final int[] nativePixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; private long drawable_old; @@ -94,25 +115,150 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, * @param comp * @param config */ - protected JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + protected JAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { if (config == null) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is null"); } if(! ( config instanceof AWTGraphicsConfiguration ) ) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config); } + appContextInfo = new AppContextInfo("<init>"); + 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(final Object obj) { return ( null!=obj ? 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(final ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentResized: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void componentMoved(final ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentMoved: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void componentShown(final ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentShown: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void componentHidden(final ComponentEvent e) { + if(DEBUG) { + System.err.println(jawtStr()+".componentHidden: "+s(e)); + } + layoutSurfaceLayerIfEnabled(isShowing); + } + + @Override + public final void hierarchyChanged(final 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)); + } + } + } + + 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; @@ -120,37 +266,88 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, drawable_old = 0; bounds = new Rectangle(); insets = new Insets(); + hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; + nativePixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + nativePixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; } protected abstract void invalidateNative(); - protected final boolean updateBounds(JAWT_Rectangle jawtBounds) { + /** + * {@inheritDoc} + * <p> + * Per default impl. only works for not yet {@link #isRealized() realized} instances, + * current exception OSX. + * </p> + */ + @Override + public void setSurfaceScale(final int[] pixelScale) { + SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null); + } + + @Override + public final int[] getRequestedSurfaceScale(final int[] result) { + System.arraycopy(reqPixelScale, 0, result, 0, 2); + return result; + } + + @Override + public final int[] getCurrentSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 0, result, 0, 2); + return result; + } + + @Override + public final int[] getNativeSurfaceScale(final int[] result) { + System.arraycopy(nativePixelScale, 0, result, 0, 2); + return result; + } + + /** + * Updates bounds and pixelScale + * @return true if bounds or pixelScale has changed, otherwise false + */ + protected final boolean updateLockedData(final 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) { + final boolean changedBounds = !bounds.equals(jb); + + if( changedBounds ) { + if( DEBUG ) { System.err.println("JAWTWindow.updateBounds: "+bounds+" -> "+jb); - Thread.dumpStack(); } - bounds.setX(jawtBounds.getX()); - bounds.setY(jawtBounds.getY()); - bounds.setWidth(jawtBounds.getWidth()); - bounds.setHeight(jawtBounds.getHeight()); - + bounds.set(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), 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); + final java.awt.Insets contInsets = ((Container)component).getInsets(); + insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom); } } - return changed; + { + final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration()); + nativePixelScale[0] = ps; + nativePixelScale[1] = ps; + } + + return updatePixelScale() || changedBounds; + } + + /** + * Update pixelScale + * @return true if pixelScale has changed, otherwise false + */ + protected final boolean updatePixelScale() { + return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null); } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } + /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */ + protected final int getPixelScaleX() { return hasPixelScale[0]; } + + /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */ + protected final int getPixelScaleY() { return hasPixelScale[1]; } + @Override public final InsetsImmutable getInsets() { return insets; } @@ -174,9 +371,9 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, // // OffscreenLayerOption // - + @Override - public void setShallUseOffscreenLayer(boolean v) { + public void setShallUseOffscreenLayer(final boolean v) { shallUseOffscreenLayer = v; } @@ -199,83 +396,126 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, 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) + ", bounds "+bounds); - } - attachSurfaceLayerImpl(layerHandle); - offscreenSurfaceLayer = layerHandle; - } finally { - unlockSurface(); + attachSurfaceLayerImpl(layerHandle); + offscreenSurfaceLayer = layerHandle; + appContextInfo.invokeOnAppContextThread(false /* waitUntilDone */, repaintTask, "Repaint"); + } + private final Runnable repaintTask = new Runnable() { + @Override + public void run() { + final Component c = component; + if( DEBUG ) { + System.err.println("Bug 1004: RepaintTask on "+Thread.currentThread()+": Has Comp "+(null != c)); + } + if( null != c ) { + c.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 + */ + protected void layoutSurfaceLayerImpl(final long layerHandle, final boolean visible) {} + + private final void layoutSurfaceLayerIfEnabled(final boolean visible) throws NativeWindowException { + if( isOffscreenLayerSurfaceEnabled() && 0 != offscreenSurfaceLayer ) { + layoutSurfaceLayerImpl(offscreenSurfaceLayer, visible); } } - protected abstract void attachSurfaceLayerImpl(final long layerHandle); + @Override public final void detachSurfaceLayer() throws NativeWindowException { - if( !isOffscreenLayerSurfaceEnabled() ) { - throw new java.lang.UnsupportedOperationException("Not an offscreen layer surface"); - } if( 0 == offscreenSurfaceLayer) { throw new NativeWindowException("No offscreen layer attached: "+this); } - 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.detachSurfaceHandle(): 0x"+Long.toHexString(offscreenSurfaceLayer)); - } - detachSurfaceLayerImpl(offscreenSurfaceLayer); - offscreenSurfaceLayer = 0; - } finally { - unlockSurface(); + if(DEBUG) { + System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer)); } + detachSurfaceLayerImpl(offscreenSurfaceLayer, detachSurfaceLayerNotify); + } + private final Runnable detachSurfaceLayerNotify = new Runnable() { + @Override + public void run() { + offscreenSurfaceLayer = 0; + } + }; + + /** + * @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"); } - protected abstract void detachSurfaceLayerImpl(final long layerHandle); - protected final long getAttachedSurfaceLayer() { + + @Override + public final long getAttachedSurfaceLayer() { return offscreenSurfaceLayer; } - + @Override public final boolean isSurfaceLayerAttached() { return 0 != offscreenSurfaceLayer; } - - @Override - public final void setChosenCapabilities(CapabilitiesImmutable caps) { - ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); - getPrivateGraphicsConfiguration().setChosenCapabilities(caps); - } - - // - // SurfaceUpdateListener - // @Override - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - surfaceUpdatedHelper.addSurfaceUpdatedListener(l); + public final void setChosenCapabilities(final CapabilitiesImmutable caps) { + ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); + config.setChosenCapabilities(caps); } @Override - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { - surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + public final RecursiveLock getLock() { + return surfaceLock; } @Override - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + 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 (final Exception e) { + e.printStackTrace(); + } + } + if( null != c ) { + component.setCursor(c); + } + } } ); + return true; } @Override - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { - surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + public final boolean hideCursor() { + AWTEDTExecutor.singleton.invoke(false, new Runnable() { + public void run() { + final Cursor cursor = AWTMisc.getNullCursor(); + if( null != cursor ) { + component.setCursor(cursor); + } + } } ); + return true; } // @@ -303,13 +543,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, 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(); } @@ -319,32 +553,41 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, 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 { - 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 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; @@ -386,19 +629,35 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } @Override - public long getSurfaceHandle() { - return drawable; + public void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); + } + + @Override + public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + @Override + public void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + @Override + public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); } - public final AWTGraphicsConfiguration getPrivateGraphicsConfiguration() { - return config; + @Override + public long getSurfaceHandle() { + return drawable; } @Override public final AbstractGraphicsConfiguration getGraphicsConfiguration() { return config.getNativeGraphicsConfiguration(); } - + @Override public final long getDisplayHandle() { return getGraphicsConfiguration().getScreen().getDevice().getHandle(); @@ -410,25 +669,55 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } @Override - public final int getWidth() { - return component.getWidth(); + public final int getSurfaceWidth() { + return getWidth() * getPixelScaleX(); } @Override - public final int getHeight() { - return component.getHeight(); + public final int getSurfaceHeight() { + return getHeight() * getPixelScaleY(); } + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + pixelUnitsAndResult[0] /= getPixelScaleX(); + pixelUnitsAndResult[1] /= getPixelScaleY(); + return pixelUnitsAndResult; + } + + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + windowUnitsAndResult[0] *= getPixelScaleX(); + windowUnitsAndResult[1] *= getPixelScaleY(); + return windowUnitsAndResult; + } + + @Override + public final NativeSurface getNativeSurface() { return this; } + // // NativeWindow // @Override + public final int getWidth() { + return component.getWidth(); + } + + @Override + public final int getHeight() { + return component.getHeight(); + } + + @Override public void destroy() { surfaceLock.lock(); try { + if(DEBUG) { + System.err.println(jawtStr()+".destroy @ Thread "+getThreadName()); + } + jawtComponentListener.detach(); invalidate(); - component = null; // don't dispose the AWT component, since we are merely an immutable uplink } finally { surfaceLock.unlock(); } @@ -478,9 +767,13 @@ 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(); + final java.awt.Point awtLOS = component.getLocationOnScreen(); if(null!=storage) { los = storage.translate(awtLOS.x, awtLOS.y); } else { @@ -490,8 +783,8 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return los; } - protected Point getLocationOnScreenNative(Point storage) { - int lockRes = lockSurface(); + protected Point getLocationOnScreenNative(final Point storage) { + final int lockRes = lockSurface(); if(LOCK_SURFACE_NOT_READY == lockRes) { if(DEBUG) { System.err.println("Warning: JAWT Lock couldn't be acquired: "+this); @@ -500,7 +793,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return null; } try { - Point d = getLocationOnScreenNativeImpl(0, 0); + final Point d = getLocationOnScreenNativeImpl(0, 0); if(null!=d) { if(null!=storage) { storage.translate(d.getX(),d.getY()); @@ -514,19 +807,33 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } 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(final 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 @@ -534,26 +841,53 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return component.hasFocus(); } + protected StringBuilder jawt2String(StringBuilder sb) { + if( null == sb ) { + sb = new StringBuilder(); + } + sb.append("JVM version: ").append(PlatformPropsImpl.JAVA_VERSION).append(" ("). + append(PlatformPropsImpl.JAVA_VERSION_NUMBER). + append(" update ").append(PlatformPropsImpl.JAVA_VERSION_UPDATE).append(")").append(Platform.getNewline()); + if(null != jawt) { + sb.append("JAWT version: ").append(toHexString(jawt.getCachedVersion())). + append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)). + append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()). + append(", bounds ").append(bounds).append(", insets ").append(insets). + append(", pixelScale ").append(getPixelScaleX()).append("x").append(getPixelScaleY()); + } 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"); - } + final StringBuilder sb = new StringBuilder(); + + 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(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+ + "], pixels[s "+getPixelScaleX()+"x"+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+ + ", visible "+component.isVisible()); sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ - ",\n\tconfig "+getPrivateGraphicsConfiguration()+ + ",\n\tconfig "+config+ ",\n\tawtComponent "+getAWTComponent()+ ",\n\tsurfaceLock "+surfaceLock+"]"); return sb.toString(); } + + protected static final String toHexString(final long l) { + return "0x"+Long.toHexString(l); + } + protected static final String toHexString(final int i) { + return "0x"+Integer.toHexString(i); + } + } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java index b824350ff..d21994ea5 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 @@ -38,14 +38,14 @@ import javax.media.nativewindow.*; */ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { final long[] nativeDisplayID = new long[1]; - final EGLDisplayLifecycleCallback eglLifecycleCallback; + /* 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> + * </p> */ public interface EGLDisplayLifecycleCallback { /** @@ -55,14 +55,14 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl * @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> @@ -73,19 +73,25 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl this.eglLifecycleCallback = null; } - public EGLGraphicsDevice(long nativeDisplayID, long eglDisplay, String connection, int unitID, EGLDisplayLifecycleCallback eglLifecycleCallback) { + public EGLGraphicsDevice(final long nativeDisplayID, final long eglDisplay, final String connection, final int unitID, final 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) { @@ -100,7 +106,13 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } 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) { @@ -111,10 +123,24 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } return super.close(); } - + + @Override + public boolean isHandleOwner() { + return null != eglLifecycleCallback; + } + @Override + public void clearHandleOwner() { + eglLifecycleCallback = null; + } + @Override + protected Object getHandleOwnership() { + return eglLifecycleCallback; + } @Override - public String toString() { - return "EGLGraphicsDevice[type EGL, connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", nativeDisplayID 0x"+Long.toHexString(nativeDisplayID[0])+", eglLifecycleCallback "+(null != eglLifecycleCallback)+"]"; + protected Object setHandleOwnership(final 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..ff149447e 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 @@ -39,10 +39,11 @@ import javax.media.nativewindow.*; public class MacOSXGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { /** Constructs a new MacOSXGraphicsDevice */ - public MacOSXGraphicsDevice(int unitID) { + public MacOSXGraphicsDevice(final int unitID) { 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 1cc796086..d29e2abbc 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java @@ -30,70 +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.DefaultGraphicsScreen; 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 com.jogamp.nativewindow.x11.X11GraphicsScreen; 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(final 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 { - Field f = null; - - final String nwt = NativeWindowFactory.getNativeWindowType(false); + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + NativeWindowFactory.initSingleton(); // last resort .. + return null; + } } ); - if(NativeWindowFactory.TYPE_MACOSX != nwt ) { + nwt = NativeWindowFactory.getNativeWindowType(false); + isOSX = NativeWindowFactory.TYPE_MACOSX == nwt; + isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt; + isX11 = NativeWindowFactory.TYPE_X11 == nwt; + + Field f = null; + if( !isOSX ) { try { f = Control.class.getField(str_handle); - } catch (Exception ex) { + } catch (final 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()); @@ -103,164 +152,291 @@ 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 }); - } catch (Exception ex) { + } catch (final Exception ex) { 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) { + } catch (final 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 == nwt ) { + 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); + final 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 (final Exception ex) { throw new NativeWindowException(ex); } + // optional + try { 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); - } catch (Exception ex) { throw new NativeWindowException(ex); } + } catch (final 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(final long arg) { if(swt_uses_long_handles) { - return new Long(arg); + return Long.valueOf(arg); } - return new Integer((int) arg); + return Integer.valueOf((int) arg); } - - static void callStaticMethodL2V(Method m, long arg) { + + private static void callStaticMethodL2V(final Method m, final long arg) { ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); } - - static long callStaticMethodL2L(Method m, long arg) { - Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); + + private static void callStaticMethodLLZ2V(final Method m, final long arg0, final long arg1, final boolean arg3) { + ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1), Boolean.valueOf(arg3) }); + } + + private static long callStaticMethodL2L(final Method m, final long arg) { + final Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); if(o instanceof Number) { return ((Number)o).longValue(); } else { 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(final 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(final 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(final 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(final long window, final long pixmap, final 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(final 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); + final 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 (final 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); - } catch (Exception ex) { + h = swt_control_handle.getLong(swtControl); + } catch (final 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); - 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(final 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 */); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + if( isWindows ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isOSX ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } - public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) { - if( null != OS_gtk_class ) { - return new X11GraphicsScreen((X11GraphicsDevice)device, screen); - } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { - return new DefaultGraphicsScreen(device, screen); - } - throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + + /** + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return + */ + public static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen) { + return NativeWindowFactory.createScreen(device, screen); } - public static int getNativeVisualID(AbstractGraphicsDevice device, long windowHandle) { - if( null != OS_gtk_class ) { + + public static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle) { + if( isX11 ) { return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return VisualIDHolder.VID_UNDEFINED; } - throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); + throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } - - 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); + + /** + * @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(final 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 ) ); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return handle; } 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 }); } @@ -274,39 +450,138 @@ 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 }); + ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { Long.valueOf(gc), gcData }); } else { - ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { new Integer((int)gc), gcData }); + ReflectionUtil.callMethod(swtControl, swt_control_internal_dispose_GC, new Object[] { Integer.valueOf((int)gc), gcData }); } } }); } - + /** * 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.</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></li> * </ul> * @see Platform#AWT_AVAILABLE * @see Platform#getOSType() */ - public static void invoke(boolean wait, Runnable runnable) { - if( Platform.OS_TYPE == Platform.OSType.MACOS ) { + public static void invoke(final boolean wait, final Runnable runnable) { + if( isOSX ) { // Use SWT main thread! Only reliable config w/ -XStartOnMainThread !? - OSXUtil.RunOnMainThread(wait, runnable); + OSXUtil.RunOnMainThread(wait, false, 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(final org.eclipse.swt.widgets.Display display, final boolean wait, final 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(final AbstractGraphicsScreen screen, final Control swtControl, final int visualID, final int width, final 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(final AbstractGraphicsDevice device, final Rectangle clientArea, final long x11Window) { + X11Lib.SetWindowPosSize(device.getHandle(), x11Window, clientArea.x, clientArea.y, clientArea.width, clientArea.height); + } + public static void destroyX11Window(final AbstractGraphicsDevice device, final 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(final Control swtControl, final int visualID, final int width, final 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(final long gdkWindow) { + /* OS.gdk_window_show (gdkWindow); + OS.gdk_flush(); */ + } + public static void focusGDKWindow(final long gdkWindow) { + /* + OS.gdk_window_show (gdkWindow); + OS.gdk_window_focus(gdkWindow, 0); + OS.gdk_flush(); */ + } + public static void resizeGDKWindow(final Rectangle clientArea, final 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(final 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..ef0cbddd7 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,19 +34,20 @@ package com.jogamp.nativewindow.windows; import javax.media.nativewindow.*; -/** +/** * Encapsulates a graphics device on Windows platforms.<br> */ public class WindowsGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { /** Constructs a new WindowsGraphicsDevice */ - public WindowsGraphicsDevice(int unitID) { + public WindowsGraphicsDevice(final int unitID) { this(AbstractGraphicsDevice.DEFAULT_CONNECTION, unitID); } - public WindowsGraphicsDevice(String connection, int unitID) { + public WindowsGraphicsDevice(final String connection, final int unitID) { 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..223cb5194 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,9 +48,9 @@ import jogamp.nativewindow.x11.XVisualInfo; public class X11GraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { private XVisualInfo info; - public X11GraphicsConfiguration(X11GraphicsScreen screen, - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - XVisualInfo info) { + public X11GraphicsConfiguration(final X11GraphicsScreen screen, + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final XVisualInfo info) { super(screen, capsChosen, capsRequested); this.info = info; } @@ -64,19 +64,19 @@ public class X11GraphicsConfiguration extends MutableGraphicsConfiguration imple return info; } - final protected void setXVisualInfo(XVisualInfo info) { + final protected void setXVisualInfo(final XVisualInfo info) { this.info = info; } 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 152384980..fea4e7019 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 @@ -45,7 +45,8 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - final boolean handleOwner; + /* 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> @@ -53,41 +54,54 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl * This constructor exist to setup a default device connection. * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int) */ - public X11GraphicsDevice(String connection, int unitID) { + public X11GraphicsDevice(final String connection, final int unitID) { super(NativeWindowFactory.TYPE_X11, connection, unitID); 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"); - } - handleOwner = owner; + public X11GraphicsDevice(final long display, final int unitID, final boolean 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) { + public X11GraphicsDevice(final long display, final int unitID, final ToolkitLock locker, final boolean owner) { super(NativeWindowFactory.TYPE_X11, X11Lib.XDisplayString(display), unitID, display, locker); if(0==display) { throw new NativeWindowException("null display"); } 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(final String displayConnection, final int unitID, final ToolkitLock locker) { + super(NativeWindowFactory.TYPE_X11, displayConnection, unitID, 0, locker); + handleOwner = true; + open(); + isXineramaEnabled = X11Util.XineramaIsEnabled(this); } - private static int getDefaultScreenImpl(long dpy) { + private static int getDefaultScreenImpl(final long dpy) { return X11Lib.DefaultScreen(dpy); } - + /** * Returns the default screen number as referenced by the display connection, i.e. 'somewhere:0.1' -> 1 * <p> @@ -105,7 +119,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } return ds; } - + public int getDefaultVisualID() { final long display = getHandle(); if(0==display) { @@ -113,7 +127,11 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } return X11Lib.DefaultVisualID(display, getDefaultScreenImpl(display)); } - + + public final boolean isXineramaEnabled() { + return isXineramaEnabled; + } + @Override public Object clone() { return super.clone(); @@ -133,7 +151,7 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } return false; } - + @Override public boolean close() { if(handleOwner && 0 != handle) { @@ -144,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(final 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 5f3c220ca..8ebf3c379 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 @@ -47,11 +49,11 @@ import jogamp.nativewindow.x11.X11Util; public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneable { /** Constructs a new X11GraphicsScreen corresponding to the given native screen index. */ - public X11GraphicsScreen(X11GraphicsDevice device, int screen) { - super(device, fetchScreen(device, screen)); + public X11GraphicsScreen(final X11GraphicsDevice device, final int screen) { + super(device, device.isXineramaEnabled() ? 0 : screen); } - public static AbstractGraphicsScreen createScreenDevice(long display, int screenIdx, boolean owner) { + public static AbstractGraphicsScreen createScreenDevice(final long display, final int screenIdx, final boolean owner) { if(0==display) throw new NativeWindowException("display is null"); return new X11GraphicsScreen(new X11GraphicsDevice(display, AbstractGraphicsDevice.DEFAULT_UNIT, owner), screenIdx); } @@ -60,15 +62,8 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl // It still could be an AWT hold handle .. return X11Lib.DefaultVisualID(getDevice().getHandle(), getIndex()); } - - 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; - } + @Override public Object clone() { return super.clone(); } |