diff options
Diffstat (limited to 'src/nativewindow')
105 files changed, 8563 insertions, 2644 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(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java index ebdaf2fbb..48f72e574 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.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. */ @@ -42,8 +42,9 @@ package javax.media.nativewindow; /** A marker interface describing a graphics configuration, visual, or pixel format in a toolkit-independent manner. */ - public interface AbstractGraphicsConfiguration extends VisualIDHolder, Cloneable { + public Object clone(); + /** * Return the screen this graphics configuration is valid for */ diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 756e4451b..31b64269f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.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. */ @@ -45,10 +45,9 @@ import jogamp.nativewindow.Debug; /** A interface describing a graphics device in a toolkit-independent manner. */ - public interface AbstractGraphicsDevice extends Cloneable { public static final boolean DEBUG = Debug.debug("GraphicsDevice"); - + /** Dummy connection value for a default connection where no native support for multiple devices is available */ public static String DEFAULT_CONNECTION = "decon"; @@ -58,6 +57,8 @@ public interface AbstractGraphicsDevice extends Cloneable { /** Default unit id for the 1st device: 0 */ public static int DEFAULT_UNIT = 0; + public Object clone(); + /** * Returns the type of the underlying subsystem, ie * NativeWindowFactory.TYPE_KD, NativeWindowFactory.TYPE_X11, .. @@ -88,10 +89,16 @@ public interface AbstractGraphicsDevice extends Cloneable { public int getUnitID(); /** - * Returns a unique ID String of this device using {@link #getType() type}, - * {@link #getConnection() connection} and {@link #getUnitID() unitID}.<br> - * The unique ID does not reflect the instance of the device, hence the handle is not included.<br> + * Returns a unique ID object of this device using {@link #getType() type}, + * {@link #getConnection() connection} and {@link #getUnitID() unitID} as it's key components. + * <p> + * The unique ID does not reflect the instance of the device, hence the handle is not included. * The unique ID may be used as a key for semantic device mapping. + * </p> + * <p> + * The returned string object reference is unique using {@link String#intern()} + * and hence can be used as a key itself. + * </p> */ public String getUniqueID(); @@ -102,27 +109,34 @@ public interface AbstractGraphicsDevice extends Cloneable { public long getHandle(); /** - * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}. + * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock#lock()}. * The lock implementation must be recursive. */ public void lock(); - /** - * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}. + /** + * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock#unlock()}. * The lock implementation must be recursive. + * + * @throws RuntimeException in case the lock is not acquired by this thread. */ public void unlock(); - /** + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + + /** * Optionally [re]opening the device if handle is <code>null</code>. * <p> * The default implementation is a <code>NOP</code>. * </p> * <p> - * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} - * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} + * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} + * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} * issue the native open operation in case handle is <code>null</code>. - * </p> + * </p> * * @return true if the handle was <code>null</code> and opening was successful, otherwise false. */ @@ -131,15 +145,22 @@ public interface AbstractGraphicsDevice extends Cloneable { /** * Optionally closing the device if handle is not <code>null</code>. * <p> - * The default implementation is a <code>NOP</code>, just setting the handle to <code>null</code>. + * The default implementation {@link ToolkitLock#dispose() dispose} it's {@link ToolkitLock} and sets the handle to <code>null</code>. * </p> * <p> - * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} - * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} - * issue the native close operation or skip it depending on the handles's ownership. - * </p> + * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} + * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} + * issue the native close operation or skip it depending on the {@link #isHandleOwner() handles's ownership}. + * </p> * * @return true if the handle was not <code>null</code> and closing was successful, otherwise false. */ public boolean close(); + + /** + * @return <code>true</code> if instance owns the handle to issue {@link #close()}, otherwise <code>false</code>. + */ + public boolean isHandleOwner(); + + public void clearHandleOwner(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java index eb2cc9120..da8f12f3e 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsScreen.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2005 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 @@ -28,11 +28,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. */ @@ -44,6 +44,8 @@ package javax.media.nativewindow; */ public interface AbstractGraphicsScreen extends Cloneable { + public Object clone(); + /** * Return the device this graphics configuration is valid for */ diff --git a/src/nativewindow/classes/javax/media/nativewindow/Capabilities.java b/src/nativewindow/classes/javax/media/nativewindow/Capabilities.java index 5795e8cfe..bf8952565 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/Capabilities.java +++ b/src/nativewindow/classes/javax/media/nativewindow/Capabilities.java @@ -61,7 +61,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { // Switch for on- or offscreen private boolean onscreen = true; - + // offscreen bitmap mode private boolean isBitmap = false; @@ -74,22 +74,22 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { public Object cloneMutable() { return clone(); } - + @Override public Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException e) { + } catch (final CloneNotSupportedException e) { throw new NativeWindowException(e); } } /** - * Copies all {@link Capabilities} values + * Copies all {@link Capabilities} values * from <code>source</code> into this instance. * @return this instance */ - public Capabilities copyFrom(CapabilitiesImmutable other) { + public Capabilities copyFrom(final CapabilitiesImmutable other) { redBits = other.getRedBits(); greenBits = other.getGreenBits(); blueBits = other.getBlueBits(); @@ -103,7 +103,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { transparentValueAlpha = other.getTransparentAlphaValue(); return this; } - + @Override public int hashCode() { // 31 * x == (x << 5) - x @@ -122,12 +122,12 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { } @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if(this == obj) { return true; } if(!(obj instanceof CapabilitiesImmutable)) { return false; } - CapabilitiesImmutable other = (CapabilitiesImmutable)obj; + final CapabilitiesImmutable other = (CapabilitiesImmutable)obj; boolean res = other.getRedBits()==redBits && other.getGreenBits()==greenBits && other.getBlueBits()==blueBits && @@ -150,18 +150,16 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { **/ @Override public int compareTo(final CapabilitiesImmutable caps) { - /** + /** if ( ! ( o instanceof CapabilitiesImmutable ) ) { Class<?> c = (null != o) ? o.getClass() : null ; throw new ClassCastException("Not a CapabilitiesImmutable object, but " + c); } final CapabilitiesImmutable caps = (CapabilitiesImmutable) o; */ - - final int a = ( alphaBits > 0 ) ? alphaBits : 1; - final int rgba = redBits * greenBits * blueBits * a; - final int xa = ( caps.getAlphaBits() ) > 0 ? caps.getAlphaBits() : 1; - final int xrgba = caps.getRedBits() * caps.getGreenBits() * caps.getBlueBits() * xa; + final int rgba = redBits * greenBits * blueBits * ( alphaBits + 1 ); + + final int xrgba = caps.getRedBits() * caps.getGreenBits() * caps.getBlueBits() * ( caps.getAlphaBits() + 1 ); if(rgba > xrgba) { return 1; @@ -173,7 +171,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { } @Override - public int getVisualID(VIDType type) throws NativeWindowException { + public int getVisualID(final VIDType type) throws NativeWindowException { switch(type) { case INTRINSIC: case NATIVE: @@ -191,7 +189,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { /** Sets the number of bits requested for the color buffer's red component. On some systems only the color depth, which is the sum of the red, green, and blue bits, is considered. */ - public void setRedBits(int redBits) { + public void setRedBits(final int redBits) { this.redBits = redBits; } @@ -203,7 +201,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { /** Sets the number of bits requested for the color buffer's green component. On some systems only the color depth, which is the sum of the red, green, and blue bits, is considered. */ - public void setGreenBits(int greenBits) { + public void setGreenBits(final int greenBits) { this.greenBits = greenBits; } @@ -215,7 +213,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { /** Sets the number of bits requested for the color buffer's blue component. On some systems only the color depth, which is the sum of the red, green, and blue bits, is considered. */ - public void setBlueBits(int blueBits) { + public void setBlueBits(final int blueBits) { this.blueBits = blueBits; } @@ -224,19 +222,19 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { return alphaBits; } - /** + /** * Sets the number of bits requested for the color buffer's alpha * component. On some systems only the color depth, which is the * sum of the red, green, and blue bits, is considered. * <p> - * <b>Note:</b> If alpha bits are <code>zero</code>, they are set to <code>one</code> + * <b>Note:</b> If alpha bits are <code>zero</code>, they are set to <code>one</code> * by {@link #setBackgroundOpaque(boolean)} and it's OpenGL specialization <code>GLCapabilities::setSampleBuffers(boolean)</code>.<br/> * Ensure to call this method after the above to ensure a <code>zero</code> value.</br> * The above automated settings takes into account, that the user calls this method to <i>request</i> alpha bits, * not to <i>reflect</i> a current state. Nevertheless if this is the case - call it at last. - * </p> + * </p> */ - public void setAlphaBits(int alphaBits) { + public void setAlphaBits(final int alphaBits) { this.alphaBits = alphaBits; } @@ -255,7 +253,7 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { * due to the composite work required by the window manager. * </p> */ - public void setBackgroundOpaque(boolean opaque) { + public void setBackgroundOpaque(final boolean opaque) { backgroundOpaque = opaque; if(!opaque && getAlphaBits()==0) { setAlphaBits(1); @@ -273,13 +271,13 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { * Defaults to true. * </p> * <p> - * If requesting an offscreen surface without further selection of it's mode, + * If requesting an offscreen surface without further selection of it's mode, * e.g. FBO, Pbuffer or {@link #setBitmap(boolean) bitmap}, * the implementation will choose the best available offscreen mode. * </p> * @param onscreen */ - public void setOnscreen(boolean onscreen) { + public void setOnscreen(final boolean onscreen) { this.onscreen=onscreen; } @@ -300,18 +298,18 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { * Requesting offscreen bitmap mode disables the offscreen auto selection. * </p> */ - public void setBitmap(boolean enable) { + public void setBitmap(final boolean enable) { if(enable) { setOnscreen(false); } isBitmap = enable; } - + @Override public boolean isBitmap() { - return isBitmap; + return isBitmap; } - + @Override public final int getTransparentRedValue() { return transparentValueRed; } @@ -329,46 +327,46 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> It defaults to half of the frambuffer value for red. <br> A value of -1 is interpreted as any value. */ - public void setTransparentRedValue(int transValueRed) { transparentValueRed=transValueRed; } + public void setTransparentRedValue(final int transValueRed) { transparentValueRed=transValueRed; } /** Sets the transparent green value for the frame buffer configuration, ranging from 0 to the maximum frame buffer value for green. This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> It defaults to half of the frambuffer value for green.<br> A value of -1 is interpreted as any value. */ - public void setTransparentGreenValue(int transValueGreen) { transparentValueGreen=transValueGreen; } + public void setTransparentGreenValue(final int transValueGreen) { transparentValueGreen=transValueGreen; } /** Sets the transparent blue value for the frame buffer configuration, ranging from 0 to the maximum frame buffer value for blue. This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> It defaults to half of the frambuffer value for blue.<br> A value of -1 is interpreted as any value. */ - public void setTransparentBlueValue(int transValueBlue) { transparentValueBlue=transValueBlue; } + public void setTransparentBlueValue(final int transValueBlue) { transparentValueBlue=transValueBlue; } /** Sets the transparent alpha value for the frame buffer configuration, ranging from 0 to the maximum frame buffer value for alpha. This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> It defaults to half of the frambuffer value for alpha.<br> A value of -1 is interpreted as any value. */ - public void setTransparentAlphaValue(int transValueAlpha) { transparentValueAlpha=transValueAlpha; } + public void setTransparentAlphaValue(final int transValueAlpha) { transparentValueAlpha=transValueAlpha; } @Override - public StringBuilder toString(StringBuilder sink) { + public StringBuilder toString(final StringBuilder sink) { return toString(sink, true); } - + /** Returns a textual representation of this Capabilities object. */ @Override public String toString() { - StringBuilder msg = new StringBuilder(); + final StringBuilder msg = new StringBuilder(); msg.append("Caps["); toString(msg); msg.append("]"); return msg.toString(); } - - /** Return a textual representation of this object's on/off screen state. Use the given StringBuffer [optional]. */ + + /** Return a textual representation of this object's on/off screen state. Use the given StringBuilder [optional]. */ protected StringBuilder onoffScreenToString(StringBuilder sink) { if(null == sink) { sink = new StringBuilder(); @@ -383,29 +381,34 @@ public class Capabilities implements CapabilitiesImmutable, Cloneable { } else if(onscreen) { sink.append("."); // no additional off-screen modes besides on-screen } else { - sink.append("auto-cfg"); // auto-config off-screen mode + sink.append("auto-cfg"); // auto-config off-screen mode } - sink.append("]"); - + sink.append("]"); + return sink; } - - protected StringBuilder toString(StringBuilder sink, boolean withOnOffScreen) { + + /** Element separator */ + protected static final String ESEP = "/"; + /** Component separator */ + protected static final String CSEP = ", "; + + protected StringBuilder toString(StringBuilder sink, final boolean withOnOffScreen) { if(null == sink) { sink = new StringBuilder(); } - sink.append("rgba 0x").append(toHexString(redBits)).append("/").append(toHexString(greenBits)).append("/").append(toHexString(blueBits)).append("/").append(toHexString(alphaBits)); + sink.append("rgba ").append(redBits).append(ESEP).append(greenBits).append(ESEP).append(blueBits).append(ESEP).append(alphaBits); if(backgroundOpaque) { sink.append(", opaque"); } else { - sink.append(", trans-rgba 0x").append(toHexString(transparentValueRed)).append("/").append(toHexString(transparentValueGreen)).append("/").append(toHexString(transparentValueBlue)).append("/").append(toHexString(transparentValueAlpha)); + sink.append(", trans-rgba 0x").append(toHexString(transparentValueRed)).append(ESEP).append(toHexString(transparentValueGreen)).append(ESEP).append(toHexString(transparentValueBlue)).append(ESEP).append(toHexString(transparentValueAlpha)); } if(withOnOffScreen) { - sink.append(", "); + sink.append(CSEP); onoffScreenToString(sink); } return sink; } - - protected final String toHexString(int val) { return Integer.toHexString(val); } + + protected final String toHexString(final int val) { return Integer.toHexString(val); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesChooser.java b/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesChooser.java index e1fdf4938..1f4db7997 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesChooser.java +++ b/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesChooser.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2003 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 @@ -28,11 +28,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. */ @@ -58,7 +58,7 @@ public interface CapabilitiesChooser { not necessarily required, that the chooser select that entry. <P> <em>Note:</em> this method is called automatically by the - {@link GraphicsConfigurationFactory#chooseGraphicsConfiguration} method + {@link GraphicsConfigurationFactory#chooseGraphicsConfiguration} method when an instance of this class is passed in to it. It should generally not be invoked by users directly, unless it is desired to delegate the diff --git a/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesImmutable.java b/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesImmutable.java index b801ab457..c496a1535 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesImmutable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/CapabilitiesImmutable.java @@ -70,12 +70,12 @@ public interface CapabilitiesImmutable extends VisualIDHolder, WriteCloneable, C * Returns whether an opaque or translucent surface is requested, supported or chosen. * <p> * Default is true, i.e. opaque. - * </p> + * </p> */ boolean isBackgroundOpaque(); /** - * Returns whether an on- or offscreen surface is requested, available or chosen. + * Returns whether an on- or offscreen surface is requested, available or chosen. * <p> * Default is true, i.e. onscreen. * </p> @@ -83,7 +83,7 @@ public interface CapabilitiesImmutable extends VisualIDHolder, WriteCloneable, C * Mind that an capabilities intance w/ <i>available</i> semantics * may show onscreen, but also the offscreen modes FBO, Pbuffer or {@link #setBitmap(boolean) bitmap}. * This is valid, since one native configuration maybe used for either functionality. - * </p> + * </p> */ boolean isOnscreen(); @@ -97,7 +97,7 @@ public interface CapabilitiesImmutable extends VisualIDHolder, WriteCloneable, C * </p> */ boolean isBitmap(); - + /** * Gets the transparent red value for the frame buffer configuration. This * value is undefined if; equals true. @@ -130,7 +130,7 @@ public interface CapabilitiesImmutable extends VisualIDHolder, WriteCloneable, C @Override int hashCode(); - /** Return a textual representation of this object. Use the given StringBuffer [optional]. */ + /** Return a textual representation of this object. Use the given StringBuilder [optional]. */ StringBuilder toString(StringBuilder sink); /** Returns a textual representation of this object. */ diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java index 744c7e6d5..d0c1a9b85 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultCapabilitiesChooser.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,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. */ @@ -42,6 +42,8 @@ package javax.media.nativewindow; import java.util.List; +import com.jogamp.common.util.PropertyAccess; + import jogamp.nativewindow.Debug; /** <P> The default implementation of the {@link @@ -66,11 +68,17 @@ import jogamp.nativewindow.Debug; */ public class DefaultCapabilitiesChooser implements CapabilitiesChooser { - private static final boolean DEBUG = Debug.isPropertyDefined("nativewindow.debug.CapabilitiesChooser", true); + private static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = PropertyAccess.isPropertyDefined("nativewindow.debug.CapabilitiesChooser", true); + } private final static int NO_SCORE = -9999999; private final static int COLOR_MISMATCH_PENALTY_SCALE = 36; - + + @Override public int chooseCapabilities(final CapabilitiesImmutable desired, final List<? extends CapabilitiesImmutable> available, final int windowSystemRecommendedChoice) { @@ -94,7 +102,7 @@ public class DefaultCapabilitiesChooser implements CapabilitiesChooser { } // Create score array - int[] scores = new int[availnum]; + final int[] scores = new int[availnum]; for (int i = 0; i < availnum; i++) { scores[i] = NO_SCORE; } @@ -107,7 +115,7 @@ public class DefaultCapabilitiesChooser implements CapabilitiesChooser { if (desired.isOnscreen() && !cur.isOnscreen()) { continue; // requested onscreen, but n/a } - + int score = 0; // Compute difference in color depth score += (COLOR_MISMATCH_PENALTY_SCALE * @@ -127,11 +135,11 @@ public class DefaultCapabilitiesChooser implements CapabilitiesChooser { System.err.println(" ]"); } - // Ready to select. Choose score closest to 0. + // Ready to select. Choose score closest to 0. int scoreClosestToZero = NO_SCORE; int chosenIndex = -1; for (int i = 0; i < availnum; i++) { - int score = scores[i]; + final int score = scores[i]; if (score == NO_SCORE) { continue; } @@ -155,7 +163,7 @@ public class DefaultCapabilitiesChooser implements CapabilitiesChooser { return chosenIndex; } - private static int sign(int score) { + private static int sign(final int score) { if (score < 0) { return -1; } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java index a33c3792a..cae37c36c 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -36,13 +36,13 @@ import jogamp.nativewindow.Debug; public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphicsConfiguration { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); - + private AbstractGraphicsScreen screen; protected CapabilitiesImmutable capabilitiesChosen; protected CapabilitiesImmutable capabilitiesRequested; - public DefaultGraphicsConfiguration(AbstractGraphicsScreen screen, - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + public DefaultGraphicsConfiguration(final AbstractGraphicsScreen screen, + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested) { if(null == screen) { throw new IllegalArgumentException("Null screen"); } @@ -52,9 +52,6 @@ public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphics if(null == capsRequested) { throw new IllegalArgumentException("Null requested caps"); } - if( ! ( capsChosen instanceof VisualIDHolder ) ) { - throw new IllegalArgumentException("Chosen caps is not implementing NativeVisualID"); - } this.screen = screen; this.capabilitiesChosen = capsChosen; this.capabilitiesRequested = capsRequested; @@ -64,69 +61,74 @@ public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphics public Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException e) { + } catch (final CloneNotSupportedException e) { throw new NativeWindowException(e); } } + @Override final public AbstractGraphicsScreen getScreen() { return screen; } + @Override final public CapabilitiesImmutable getChosenCapabilities() { return capabilitiesChosen; } + @Override final public CapabilitiesImmutable getRequestedCapabilities() { return capabilitiesRequested; } + @Override public AbstractGraphicsConfiguration getNativeGraphicsConfiguration() { return this; } @Override - final public int getVisualID(VIDType type) throws NativeWindowException { + final public int getVisualID(final VIDType type) throws NativeWindowException { return capabilitiesChosen.getVisualID(type); } - + /** * Set the capabilities to a new value. * + * <p> * The use case for setting the Capabilities at a later time is - * a change of the graphics device in a multi-screen environment.<br> - * + * a change or re-validation of capabilities. + * </p> * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ - protected void setChosenCapabilities(CapabilitiesImmutable capsChosen) { - capabilitiesChosen = capsChosen; + protected void setChosenCapabilities(final CapabilitiesImmutable capsChosen) { + this.capabilitiesChosen = capsChosen; } /** * Set a new screen. * + * <p> * the use case for setting a new screen at a later time is - * a change of the graphics device in a multi-screen environment.<br> - * - * A copy of the passed object is being used. + * a change of the graphics device in a multi-screen environment. + * </p> */ - final protected void setScreen(DefaultGraphicsScreen screen) { - this.screen = (AbstractGraphicsScreen) screen.clone(); + protected void setScreen(final AbstractGraphicsScreen screen) { + this.screen = screen; } @Override public String toString() { return getClass().getSimpleName()+"[" + screen + ",\n\tchosen " + capabilitiesChosen+ - ",\n\trequested " + capabilitiesRequested+ + ",\n\trequested " + capabilitiesRequested+ "]"; } - public static String toHexString(int val) { + public static String toHexString(final int val) { return "0x"+Integer.toHexString(val); } - public static String toHexString(long val) { + public static String toHexString(final long val) { return "0x"+Long.toHexString(val); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index 583fde07f..ab9286b3f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.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 @@ -37,10 +37,10 @@ import jogamp.nativewindow.NativeWindowFactoryImpl; public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice { private static final String separator = "_"; - private String type; - protected String connection; - protected int unitID; - protected String uniqueID; + private final String type; + protected final String connection; + protected final int unitID; + protected final String uniqueID; protected long handle; protected ToolkitLock toolkitLock; @@ -49,37 +49,27 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String)}. * @param type */ - public DefaultGraphicsDevice(String type, String connection, int unitID) { - this.type = type; - this.connection = connection; - this.unitID = unitID; - this.uniqueID = getUniqueID(type, connection, unitID); - this.handle = 0; - this.toolkitLock = NativeWindowFactory.getDefaultToolkitLock(type); + public DefaultGraphicsDevice(final String type, final String connection, final int unitID) { + this(type, connection, unitID, 0, NativeWindowFactory.getDefaultToolkitLock(type)); } /** * Create an instance with the system default {@link ToolkitLock}. - * gathered via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. * @param type * @param handle */ - public DefaultGraphicsDevice(String type, String connection, int unitID, long handle) { - this.type = type; - this.connection = connection; - this.unitID = unitID; - this.uniqueID = getUniqueID(type, connection, unitID); - this.handle = handle; - this.toolkitLock = NativeWindowFactory.createDefaultToolkitLock(type, handle); + public DefaultGraphicsDevice(final String type, final String connection, final int unitID, final long handle) { + this(type, connection, unitID, handle, NativeWindowFactory.getDefaultToolkitLock(type, handle)); } /** - * Create an instance with the given {@link ToolkitLock} instance. + * Create an instance with the given {@link ToolkitLock} instance, or <i>null</i> {@link ToolkitLock} if null. * @param type * @param handle - * @param locker + * @param locker if null, a non blocking <i>null</i> lock is used. */ - public DefaultGraphicsDevice(String type, String connection, int unitID, long handle, ToolkitLock locker) { + public DefaultGraphicsDevice(final String type, final String connection, final int unitID, final long handle, final ToolkitLock locker) { this.type = type; this.connection = connection; this.unitID = unitID; @@ -92,7 +82,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice public Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException e) { + } catch (final CloneNotSupportedException e) { throw new NativeWindowException(e); } } @@ -123,8 +113,10 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } /** - * No lock is performed on the graphics device per default, - * instead the aggregated recursive {@link ToolkitLock#lock()} is invoked. + * {@inheritDoc} + * <p> + * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}. + * </p> * * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) @@ -134,9 +126,16 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice toolkitLock.lock(); } - /** - * No lock is performed on the graphics device per default, - * instead the aggregated recursive {@link ToolkitLock#unlock()} is invoked. + @Override + public final void validateLocked() throws RuntimeException { + toolkitLock.validateLocked(); + } + + /** + * {@inheritDoc} + * <p> + * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}. + * </p> * * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) @@ -145,7 +144,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice public final void unlock() { toolkitLock.unlock(); } - + @Override public boolean open() { return false; @@ -153,6 +152,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice @Override public boolean close() { + toolkitLock.dispose(); if(0 != handle) { handle = 0; return true; @@ -161,8 +161,53 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } @Override + public boolean isHandleOwner() { + return false; + } + + @Override + public void clearHandleOwner() { + } + + @Override public String toString() { - return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+"]"; + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", owner "+isHandleOwner()+", "+toolkitLock+"]"; + } + + /** + * Set the native handle of the underlying native device + * and return the previous one. + */ + protected final long setHandle(final long newHandle) { + final long oldHandle = handle; + handle = newHandle; + return oldHandle; + } + + protected Object getHandleOwnership() { + return null; + } + protected Object setHandleOwnership(final Object newOwnership) { + return null; + } + + public static final void swapDeviceHandleAndOwnership(final DefaultGraphicsDevice aDevice1, final DefaultGraphicsDevice aDevice2) { + aDevice1.lock(); + try { + aDevice2.lock(); + try { + final long aDevice1Handle = aDevice1.getHandle(); + final long aDevice2Handle = aDevice2.setHandle(aDevice1Handle); + aDevice1.setHandle(aDevice2Handle); + final Object aOwnership1 = aDevice1.getHandleOwnership(); + final Object aOwnership2 = aDevice2.setHandleOwnership(aOwnership1); + aDevice1.setHandleOwnership(aOwnership2); + } finally { + aDevice2.unlock(); + } + } finally { + aDevice1.unlock(); + } } /** @@ -173,10 +218,11 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice * The current ToolkitLock is being locked/unlocked while swapping the reference, * ensuring no concurrent access can occur during the swap. * </p> - * + * * @param locker the ToolkitLock, if null, {@link jogamp.nativewindow.NullToolkitLock} is being used + * @return the previous ToolkitLock instance */ - protected void setToolkitLock(ToolkitLock locker) { + protected ToolkitLock setToolkitLock(final ToolkitLock locker) { final ToolkitLock _toolkitLock = toolkitLock; _toolkitLock.lock(); try { @@ -184,6 +230,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } finally { _toolkitLock.unlock(); } + return _toolkitLock; } /** @@ -196,7 +243,11 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice return toolkitLock; } - protected static String getUniqueID(String type, String connection, int unitID) { + /** + * Returns a unique String object using {@link String#intern()} for the given arguments, + * which object reference itself can be used as a key. + */ + private static String getUniqueID(final String type, final String connection, final int unitID) { return (type + separator + connection + separator + unitID).intern(); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java index f50bd0e14..3ee775904 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsScreen.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 @@ -33,15 +33,15 @@ package javax.media.nativewindow; public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen { - AbstractGraphicsDevice device; - private int idx; + private final AbstractGraphicsDevice device; + private final int idx; - public DefaultGraphicsScreen(AbstractGraphicsDevice device, int idx) { + public DefaultGraphicsScreen(final AbstractGraphicsDevice device, final int idx) { this.device = device; this.idx = idx; } - public static AbstractGraphicsScreen createDefault(String type) { + public static AbstractGraphicsScreen createDefault(final String type) { return new DefaultGraphicsScreen(new DefaultGraphicsDevice(type, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT), 0); } @@ -49,15 +49,17 @@ public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen public Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException e) { + } catch (final CloneNotSupportedException e) { throw new NativeWindowException(e); } } + @Override public AbstractGraphicsDevice getDevice() { return device; } + @Override public int getIndex() { return idx; } diff --git a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index 9694f2491..3f8113baa 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -48,7 +48,7 @@ import java.util.Set; /** * Provides the mechanism by which the graphics configuration for a - * window can be chosen before the window is created. The graphics + * window can be chosen before the window is created. The graphics * configuration decides parameters related to hardware accelerated rendering such * as the OpenGL pixel format. <br> * On some window systems (EGL/OpenKODE and X11 in particular) it is necessary to @@ -69,41 +69,43 @@ public abstract class GraphicsConfigurationFactory { public final Class<?> deviceType; public final Class<?> capsType; private final int hash32; - - public DeviceCapsType(Class<?> deviceType, Class<?> capsType) { + + public DeviceCapsType(final Class<?> deviceType, final Class<?> capsType) { this.deviceType = deviceType; this.capsType = capsType; - + // 31 * x == (x << 5) - x int hash32 = 31 + deviceType.hashCode(); hash32 = ((hash32 << 5) - hash32) + capsType.hashCode(); this.hash32 = hash32; } - + + @Override public final int hashCode() { return hash32; } - - public final boolean equals(Object obj) { + + @Override + public final boolean equals(final Object obj) { if(this == obj) { return true; } if (obj instanceof DeviceCapsType) { - DeviceCapsType dct = (DeviceCapsType)obj; + final DeviceCapsType dct = (DeviceCapsType)obj; return deviceType == dct.deviceType && capsType == dct.capsType; } return false; } - + @Override public final String toString() { return "DeviceCapsType["+deviceType.getName()+", "+capsType.getName()+"]"; } - + } - + private static final Map<DeviceCapsType, GraphicsConfigurationFactory> registeredFactories; - private static final DeviceCapsType defaultDeviceCapsType; + private static final DeviceCapsType defaultDeviceCapsType; static boolean initialized = false; - + static { DEBUG = Debug.debug("GraphicsConfiguration"); if(DEBUG) { @@ -113,7 +115,7 @@ public abstract class GraphicsConfigurationFactory { registeredFactories = Collections.synchronizedMap(new HashMap<DeviceCapsType, GraphicsConfigurationFactory>()); defaultDeviceCapsType = new DeviceCapsType(AbstractGraphicsDevice.class, CapabilitiesImmutable.class); } - + public static synchronized void initSingleton() { if(!initialized) { initialized = true; @@ -121,31 +123,31 @@ public abstract class GraphicsConfigurationFactory { if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.initSingleton()"); } - + // Register the default no-op factory for arbitrary // AbstractGraphicsDevice implementations, including // AWTGraphicsDevice instances -- the OpenGL binding will take // care of handling AWTGraphicsDevices on X11 platforms (as // well as X11GraphicsDevices in non-AWT situations) registerFactory(defaultDeviceCapsType.deviceType, defaultDeviceCapsType.capsType, new DefaultGraphicsConfigurationFactoryImpl()); - + if (NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true)) { try { - ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", - "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); - } catch (Exception e) { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (final Exception e) { throw new RuntimeException(e); } if(NativeWindowFactory.isAWTAvailable()) { try { - ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.awt.X11AWTGraphicsConfigurationFactory", - "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); - } catch (Exception e) { /* n/a */ } + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.awt.X11AWTGraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (final Exception e) { /* n/a */ } } } } } - + public static synchronized void shutdown() { if(initialized) { initialized = false; @@ -155,16 +157,16 @@ public abstract class GraphicsConfigurationFactory { registeredFactories.clear(); } } - + protected static String getThreadName() { return Thread.currentThread().getName(); } - protected static String toHexString(int val) { + protected static String toHexString(final int val) { return "0x" + Integer.toHexString(val); } - protected static String toHexString(long val) { + protected static String toHexString(final long val) { return "0x" + Long.toHexString(val); } @@ -176,10 +178,10 @@ public abstract class GraphicsConfigurationFactory { /** * Returns the graphics configuration factory for use with the * given device and capability. - * + * * @see #getFactory(Class, Class) */ - public static GraphicsConfigurationFactory getFactory(AbstractGraphicsDevice device, CapabilitiesImmutable caps) { + public static GraphicsConfigurationFactory getFactory(final AbstractGraphicsDevice device, final CapabilitiesImmutable caps) { if (device == null) { throw new IllegalArgumentException("null device"); } @@ -195,7 +197,7 @@ public abstract class GraphicsConfigurationFactory { * <p> * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only. * </p> - * + * * <p> * Pseudo code for finding a suitable factory is: * <pre> @@ -211,10 +213,10 @@ public abstract class GraphicsConfigurationFactory { * @param deviceType the minimum capabilities class type accepted, must implement or extend {@link AbstractGraphicsDevice} * @param capabilitiesType the minimum capabilities class type accepted, must implement or extend {@link CapabilitiesImmutable} * - * @throws IllegalArgumentException if the deviceType does not implement {@link AbstractGraphicsDevice} or + * @throws IllegalArgumentException if the deviceType does not implement {@link AbstractGraphicsDevice} or * capabilitiesType does not implement {@link CapabilitiesImmutable} */ - public static GraphicsConfigurationFactory getFactory(Class<?> deviceType, Class<?> capabilitiesType) + public static GraphicsConfigurationFactory getFactory(final Class<?> deviceType, final Class<?> capabilitiesType) throws IllegalArgumentException, NativeWindowException { if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(deviceType))) { @@ -228,19 +230,19 @@ public abstract class GraphicsConfigurationFactory { System.err.println("GraphicsConfigurationFactory.getFactory: "+deviceType.getName()+", "+capabilitiesType.getName()); dumpFactories(); } - - final List<Class<?>> deviceTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.deviceType, deviceType, false); + + final List<Class<?>> deviceTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.deviceType, deviceType, false); if(DEBUG) { System.err.println("GraphicsConfigurationFactory.getFactory() deviceTypes: " + deviceTypes); } - final List<Class<?>> capabilitiesTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.capsType, capabilitiesType, true); + final List<Class<?>> capabilitiesTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.capsType, capabilitiesType, true); if(DEBUG) { System.err.println("GraphicsConfigurationFactory.getFactory() capabilitiesTypes: " + capabilitiesTypes); } for(int j=0; j<deviceTypes.size(); j++) { final Class<?> interfaceDevice = deviceTypes.get(j); for(int i=0; i<capabilitiesTypes.size(); i++) { - Class<?> interfaceCaps = capabilitiesTypes.get(i); + final Class<?> interfaceCaps = capabilitiesTypes.get(i); final DeviceCapsType dct = new DeviceCapsType(interfaceDevice, interfaceCaps); final GraphicsConfigurationFactory factory = registeredFactories.get(dct); if (factory != null) { @@ -258,8 +260,8 @@ public abstract class GraphicsConfigurationFactory { } return factory; } - private static ArrayList<Class<?>> getAllAssignableClassesFrom(Class<?> superClassOrInterface, Class<?> fromClass, boolean interfacesOnly) { - // Using a todo list avoiding a recursive loop! + private static ArrayList<Class<?>> getAllAssignableClassesFrom(final Class<?> superClassOrInterface, final Class<?> fromClass, final boolean interfacesOnly) { + // Using a todo list avoiding a recursive loop! final ArrayList<Class<?>> inspectClasses = new ArrayList<Class<?>>(); final ArrayList<Class<?>> resolvedInterfaces = new ArrayList<Class<?>>(); inspectClasses.add(fromClass); @@ -269,7 +271,7 @@ public abstract class GraphicsConfigurationFactory { } return resolvedInterfaces; } - private static void getAllAssignableClassesFrom(Class<?> superClassOrInterface, Class<?> fromClass, boolean interfacesOnly, List<Class<?>> resolvedInterfaces, List<Class<?>> inspectClasses) { + private static void getAllAssignableClassesFrom(final Class<?> superClassOrInterface, final Class<?> fromClass, final boolean interfacesOnly, final List<Class<?>> resolvedInterfaces, final List<Class<?>> inspectClasses) { final ArrayList<Class<?>> types = new ArrayList<Class<?>>(); if( superClassOrInterface.isAssignableFrom(fromClass) && !resolvedInterfaces.contains(fromClass)) { if( !interfacesOnly || fromClass.isInterface() ) { @@ -277,7 +279,7 @@ public abstract class GraphicsConfigurationFactory { } } types.addAll(Arrays.asList(fromClass.getInterfaces())); - + for(int i=0; i<types.size(); i++) { final Class<?> iface = types.get(i); if( superClassOrInterface.isAssignableFrom(iface) && !resolvedInterfaces.contains(iface) ) { @@ -293,35 +295,35 @@ public abstract class GraphicsConfigurationFactory { } } private static void dumpFactories() { - Set<DeviceCapsType> dcts = registeredFactories.keySet(); + final Set<DeviceCapsType> dcts = registeredFactories.keySet(); int i=0; - for(Iterator<DeviceCapsType> iter = dcts.iterator(); iter.hasNext(); ) { - DeviceCapsType dct = iter.next(); + for(final Iterator<DeviceCapsType> iter = dcts.iterator(); iter.hasNext(); ) { + final DeviceCapsType dct = iter.next(); System.err.println("Factory #"+i+": "+dct+" -> "+registeredFactories.get(dct)); i++; } } - /** + /** * Registers a GraphicsConfigurationFactory handling * the given graphics device and capability class. * <p> * This does not need to be called by end users, only implementors of new * GraphicsConfigurationFactory subclasses. * </p> - * + * * <p> * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only. - * </p> - * + * </p> + * * <p>See {@link #getFactory(Class, Class)} for a description of the find algorithm.</p> - * + * * @param deviceType the minimum capabilities class type accepted, must implement or extend interface {@link AbstractGraphicsDevice} * @param capabilitiesType the minimum capabilities class type accepted, must extend interface {@link CapabilitiesImmutable} * @return the previous registered factory, or null if none * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice */ - protected static GraphicsConfigurationFactory registerFactory(Class<?> abstractGraphicsDeviceImplementor, Class<?> capabilitiesType, GraphicsConfigurationFactory factory) + protected static GraphicsConfigurationFactory registerFactory(final Class<?> abstractGraphicsDeviceImplementor, final Class<?> capabilitiesType, final GraphicsConfigurationFactory factory) throws IllegalArgumentException { if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(abstractGraphicsDeviceImplementor))) { @@ -329,7 +331,7 @@ public abstract class GraphicsConfigurationFactory { } if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) { throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable"); - } + } final DeviceCapsType dct = new DeviceCapsType(abstractGraphicsDeviceImplementor, capabilitiesType); final GraphicsConfigurationFactory prevFactory; if(null == factory) { @@ -352,7 +354,7 @@ public abstract class GraphicsConfigurationFactory { * <P> Selects a graphics configuration on the specified graphics * device compatible with the supplied {@link Capabilities}. Some * platforms (e.g.: X11, EGL, KD) require the graphics configuration - * to be specified when the native window is created. + * to be specified when the native window is created. * These architectures have seperated their device, screen, window and drawable * context and hence are capable of quering the capabilities for each screen. * A fully established window is not required.</P> @@ -360,7 +362,7 @@ public abstract class GraphicsConfigurationFactory { * <P>Other platforms (e.g. Windows, MacOSX) don't offer the mentioned seperation * and hence need a fully established window and it's drawable. * Here the validation of the capabilities is performed later. - * In this case, the AbstractGraphicsConfiguration implementation + * In this case, the AbstractGraphicsConfiguration implementation * must allow an overwrite of the Capabilites, for example * {@link DefaultGraphicsConfiguration#setChosenCapabilities DefaultGraphicsConfiguration.setChosenCapabilities(..)}. * </P> @@ -385,7 +387,7 @@ public abstract class GraphicsConfigurationFactory { * @param capsRequested the original requested capabilities * @param chooser the choosing implementation * @param screen the referring Screen - * @param nativeVisualID if not {@link VisualIDHolder#VID_UNDEFINED} it reflects a pre-chosen visualID of the native platform's windowing system. + * @param nativeVisualID if not {@link VisualIDHolder#VID_UNDEFINED} it reflects a pre-chosen visualID of the native platform's windowing system. * @return the complete GraphicsConfiguration * * @throws IllegalArgumentException if the data type of the passed @@ -398,9 +400,9 @@ public abstract class GraphicsConfigurationFactory { * @see javax.media.nativewindow.DefaultGraphicsConfiguration#setChosenCapabilities(Capabilities caps) */ public final AbstractGraphicsConfiguration - chooseGraphicsConfiguration(CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, - AbstractGraphicsScreen screen, int nativeVisualID) + chooseGraphicsConfiguration(final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, + final AbstractGraphicsScreen screen, final int nativeVisualID) throws IllegalArgumentException, NativeWindowException { if(null==capsChosen) { throw new NativeWindowException("Chosen Capabilities are null"); @@ -411,7 +413,7 @@ public abstract class GraphicsConfigurationFactory { if(null==screen) { throw new NativeWindowException("Screen is null"); } - AbstractGraphicsDevice device = screen.getDevice(); + final AbstractGraphicsDevice device = screen.getDevice(); if(null==device) { throw new NativeWindowException("Screen's Device is null"); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/MutableSurface.java b/src/nativewindow/classes/javax/media/nativewindow/MutableSurface.java index ff53c8109..a0db11ad9 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/MutableSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/MutableSurface.java @@ -31,12 +31,12 @@ package javax.media.nativewindow; /** * Provides a {@link NativeSurface} with a mutable <code>surfaceHandle</code> * via {@link #setSurfaceHandle(long)}. - * + * * @see NativeSurface */ public interface MutableSurface extends NativeSurface { - /** + /** * Sets the surface handle which is created outside of this implementation. */ public void setSurfaceHandle(long surfaceHandle); diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java index 27462ae70..4d764dc4f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.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,33 +20,39 @@ * 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 javax.media.nativewindow; -/** Provides low-level information required for - hardware-accelerated rendering using a surface in a platform-independent manner.<P> +package javax.media.nativewindow; - A NativeSurface created for a particular on- or offscreen component is - expected to have the same lifetime as that component. As long as - the component is alive and realized/visible, NativeSurface must be able - provide information such as the surface handle while it is locked.<P> -*/ +/** + * Provides low-level information required for + * hardware-accelerated rendering using a surface in a platform-independent manner. + * <p> + * All values of this interface are represented in pixel units, if not stated otherwise. + * See {@link NativeWindow}. + * </p> + * <p> + * A NativeSurface created for a particular on- or offscreen component is + * expected to have the same lifetime as that component. As long as + * the component is alive and realized/visible, NativeSurface must be able + * provide information such as the surface handle while it is locked. + * </p> + */ public interface NativeSurface extends SurfaceUpdatedListener { - /** Unlocked state */ + /** Unlocked state, {@value}. */ public static final int LOCK_SURFACE_UNLOCKED = 0; - /** Returned by {@link #lockSurface()} if the surface is not ready to be locked. */ + /** Returned by {@link #lockSurface()} if the surface is not ready to be locked, {@value}. */ public static final int LOCK_SURFACE_NOT_READY = 1; - /** Returned by {@link #lockSurface()} if the surface is locked, but has changed. */ + /** Returned by {@link #lockSurface()} if the surface is locked, but has changed, {@value}. */ public static final int LOCK_SURFACE_CHANGED = 2; - /** Returned by {@link #lockSurface()} if the surface is locked, and is unchanged. */ + /** Returned by {@link #lockSurface()} if the surface is locked, and is unchanged, {@value}. */ public static final int LOCK_SUCCESS = 3; /** @@ -54,10 +60,10 @@ public interface NativeSurface extends SurfaceUpdatedListener { * <p> * The surface handle shall be valid after a successfull call, * ie return a value other than {@link #LOCK_SURFACE_UNLOCKED} and {@link #LOCK_SURFACE_NOT_READY}, - * which is - * <pre> - * boolean ok = lockSurface() > LOCK_SURFACE_NOT_READY; - * </pre> + * which is + * <pre> + * boolean ok = LOCK_SURFACE_NOT_READY < lockSurface(); + * </pre> * </p> * <p> * The caller may need to take care of the result {@link #LOCK_SURFACE_CHANGED}, @@ -71,7 +77,7 @@ public interface NativeSurface extends SurfaceUpdatedListener { * This call allows recursion from the same thread. * </p> * <p> - * The implementation may want to aquire the + * The implementation may want to aquire the * application level {@link com.jogamp.common.util.locks.RecursiveLock} * first before proceeding with a native surface lock. * </p> @@ -115,7 +121,7 @@ public interface NativeSurface extends SurfaceUpdatedListener { * </pre> */ public boolean isSurfaceLockedByOtherThread(); - + /** * Return the locking owner's Thread, or null if not locked. */ @@ -123,15 +129,15 @@ public interface NativeSurface extends SurfaceUpdatedListener { /** * Provide a mechanism to utilize custom (pre-) swap surface - * code. This method is called before the render toolkit (e.g. JOGL) + * code. This method is called before the render toolkit (e.g. JOGL) * swaps the buffer/surface if double buffering is enabled. - * <p> + * <p> * The implementation may itself apply the swapping, * in which case true shall be returned. * </p> * * @return true if this method completed swapping the surface, - * otherwise false, in which case eg the GLDrawable + * otherwise false, in which case eg the GLDrawable * implementation has to swap the code. */ public boolean surfaceSwap(); @@ -153,13 +159,13 @@ public interface NativeSurface extends SurfaceUpdatedListener { /** Remove the specified {@link SurfaceUpdatedListener} from the list. */ public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); - + /** * Returns the handle to the surface for this NativeSurface. <P> - * + * * The surface handle should be set/update by {@link #lockSurface()}, * where {@link #unlockSurface()} is not allowed to modify it. - * After {@link #unlockSurface()} it is no more guaranteed + * After {@link #unlockSurface()} it is no more guaranteed * that the surface handle is still valid. * * The surface handle shall reflect the platform one @@ -172,16 +178,36 @@ public interface NativeSurface extends SurfaceUpdatedListener { public long getSurfaceHandle(); /** - * Returns the width of the client area excluding insets (window decorations). - * @return width of the client area + * Returns the width of the client area excluding insets (window decorations) in pixel units. + * @return width of the client area in pixel units + * @see NativeWindow#getWidth() + * @see #convertToWindowUnits(int[]) + */ + public int getSurfaceWidth(); + + /** + * Returns the height of the client area excluding insets (window decorations) in pixel units. + * @return height of the client area in pixel units + * @see NativeWindow#getHeight() + * @see #convertToWindowUnits(int[]) */ - public int getWidth(); + public int getSurfaceHeight(); /** - * Returns the height of the client area excluding insets (window decorations). - * @return height of the client area + * Converts the given pixel units into window units <i>in place</i>. + * @param pixelUnitsAndResult int[2] storage holding the pixel units for the x- and y-coord to convert + * and the resulting values. + * @return result int[2] storage pixelUnitsAndResult for chaining holding the converted values */ - public int getHeight(); + public int[] convertToWindowUnits(final int[] pixelUnitsAndResult); + + /** + * Converts the given window units into pixel units <i>in place</i>. + * @param windowUnitsAndResult int[2] storage holding the window units for the x- and y-coord to convert + * and the resulting values. + * @return result int[2] storage windowUnitsAndResult for chaining holding the converted values + */ + public int[] convertToPixelUnits(final int[] windowUnitsAndResult); /** * Returns the graphics configuration corresponding to this window. @@ -195,16 +221,16 @@ public interface NativeSurface extends SurfaceUpdatedListener { public AbstractGraphicsConfiguration getGraphicsConfiguration(); /** - * Convenience: Get display handle from + * Convenience: Get display handle from * AbstractGraphicsConfiguration . AbstractGraphicsScreen . AbstractGraphicsDevice */ public long getDisplayHandle(); /** - * Convenience: Get display handle from + * Convenience: Get display handle from * AbstractGraphicsConfiguration . AbstractGraphicsScreen */ public int getScreenIndex(); - + } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurfaceHolder.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurfaceHolder.java new file mode 100644 index 000000000..b459ab74a --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurfaceHolder.java @@ -0,0 +1,41 @@ +/** + * Copyright 2014 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 javax.media.nativewindow; + +/** + * Accessor interface for implementing classes with ownership of a {@link NativeSurface} + * via an <i>is-a</i> or <i>has-a</i> relation. + */ +public interface NativeSurfaceHolder { + /** + * Returns the associated {@link NativeSurface} of this {@link NativeSurfaceHolder}. + */ + public NativeSurface getNativeSurface(); +} + diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index 12e202975..7f71bc33b 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -43,19 +43,44 @@ package javax.media.nativewindow; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; -/** Extend the {@link NativeSurface} interface with windowing - information such as window handle and position.<P> +/** + * Extend the {@link NativeSurface} interface with windowing + * information such as {@link #getWindowHandle() window-handle}, + * {@link #getWidth() window-size} and {@link #getX() window-position}. + * <p> + * All values of this interface are represented in window units, if not stated otherwise. + * See {@link NativeSurface}. + * </p> + * + * <a name="coordinateSystem"><h5>Coordinate System</h5></a> + * <p> + * <ul> + * <li>Abstract screen space has it's origin in the top-left corner, and may not be at 0/0.</li> + * <li>Window origin is in it's top-left corner, see {@link #getX()} and {@link #getY()}. </li> + * <li>Window client-area excludes {@link #getInsets() insets}, i.e. window decoration.</li> + * <li>Window origin is relative to it's parent window if exist, or the screen position (top-level).</li> + * </ul> + * </p> + * <p> + * A window toolkit such as the AWT may either implement this interface + * directly with one of its components, or provide and register an + * implementation of {@link NativeWindowFactory NativeWindowFactory} + * which can create NativeWindow objects for its components. + * </p> + */ +public interface NativeWindow extends NativeSurface, NativeSurfaceHolder { - A window toolkit such as the AWT may either implement this interface - directly with one of its components, or provide and register an - implementation of {@link NativeWindowFactory NativeWindowFactory} - which can create NativeWindow objects for its components. <P> -*/ -public interface NativeWindow extends NativeSurface { + /** + * {@inheritDoc} + * <p> + * Returns this instance, which <i>is-a</i> {@link NativeSurface}. + * </p> + */ + @Override + public NativeSurface getNativeSurface(); /** - * destroys the window and releases - * windowing related resources. + * Destroys this window incl. releasing all related resources. */ public void destroy(); @@ -77,8 +102,10 @@ public interface NativeWindow extends NativeSurface { /** * Returns the insets defined as the width and height of the window decoration - * on the left, right, top and bottom.<br> + * on the left, right, top and bottom in window units. + * <p> * Insets are zero if the window is undecorated, including child windows. + * </p> * * <p> * Insets are available only after the native window has been created, @@ -86,14 +113,14 @@ public interface NativeWindow extends NativeSurface { * * The top-level window area's top-left corner is located at * <pre> - * getX() - getInsets().{@link InsetsImmutable#getLeftWidth() getLeftWidth()} - * getY() - getInsets().{@link InsetsImmutable#getTopHeight() getTopHeight()} + * {@link #getX()} - getInsets().{@link InsetsImmutable#getLeftWidth() getLeftWidth()} + * {@link #getY()} - getInsets().{@link InsetsImmutable#getTopHeight() getTopHeight()} * </pre> * * The top-level window size is * <pre> - * getWidth() + getInsets().{@link InsetsImmutable#getTotalWidth() getTotalWidth()} - * getHeight() + getInsets().{@link InsetsImmutable#getTotalHeight() getTotalHeight()} + * {@link #getWidth()} + getInsets().{@link InsetsImmutable#getTotalWidth() getTotalWidth()} + * {@link #getHeight()} + getInsets().{@link InsetsImmutable#getTotalHeight() getTotalHeight()} * </pre> * * @return insets @@ -103,32 +130,71 @@ public interface NativeWindow extends NativeSurface { /** Returns the current x position of this window, relative to it's parent. */ /** - * @return the current x position of the top-left corner - * of the client area relative to it's parent. - * Since the position reflects the client area, it does not include the insets. + * Returns the x position of the top-left corner + * of the client area relative to it's parent in window units. + * <p> + * If no parent exist (top-level window), this coordinate equals the screen coordinate. + * </p> + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> + * <p> + * See <a href="#coordinateSystem"> Coordinate System</a>. + * </p> * @see #getInsets() + * @see #getLocationOnScreen(Point) */ public int getX(); /** - * @return the current y position of the top-left corner - * of the client area relative to it's parent. - * Since the position reflects the client area, it does not include the insets. + * Returns the current y position of the top-left corner + * of the client area relative to it's parent in window units. + * <p> + * If no parent exist (top-level window), this coordinate equals the screen coordinate. + * </p> + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> + * <p> + * See <a href="#coordinateSystem"> Coordinate System</a>. + * </p> * @see #getInsets() + * @see #getLocationOnScreen(Point) */ public int getY(); /** - * Returns the current position of the top-left corner - * of the client area in screen coordinates. + * Returns the width of the client area excluding insets (window decorations) in window units. + * @return width of the client area in window units + * @see NativeSurface#getSurfaceWidth() + */ + public int getWidth(); + + /** + * Returns the height of the client area excluding insets (window decorations) in window units. + * @return height of the client area in window units + * @see NativeSurface#getSurfaceHeight() + */ + public int getHeight(); + + /** + * Returns the window's top-left client-area position in the screen. + * <p> + * If {@link Point} is not <code>null</code>, it is translated about the resulting screen position + * and returned. + * </p> + * <p> + * See <a href="#coordinateSystem"> Coordinate System</a>. + * </p> * <p> * Since the position reflects the client area, it does not include the insets. * </p> - * @param point if not null, - * {@link javax.media.nativewindow.util.Point#translate(javax.media.nativewindow.util.Point)} - * the passed {@link javax.media.nativewindow.util.Point} by this location on the screen and return it. - * @return either the passed non null translated point by the screen location of this NativeWindow, - * or a new instance with the screen location of this NativeWindow. + * @param point Optional {@link Point} storage. + * If not null, <code>null</code>, it is translated about the resulting screen position + * and returned. + * @see #getX() + * @see #getY() + * @see #getInsets() */ public Point getLocationOnScreen(Point point); diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowException.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowException.java index 593c1e7d6..16355032f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowException.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowException.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2003 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 @@ -28,11 +28,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. */ @@ -50,19 +50,19 @@ public class NativeWindowException extends RuntimeException { /** Constructs a NativeWindowException object with the specified detail message. */ - public NativeWindowException(String message) { + public NativeWindowException(final String message) { super(message); } /** Constructs a NativeWindowException object with the specified detail message and root cause. */ - public NativeWindowException(String message, Throwable cause) { + public NativeWindowException(final String message, final Throwable cause) { super(message, cause); } /** Constructs a NativeWindowException object with the specified root cause. */ - public NativeWindowException(Throwable cause) { + public NativeWindowException(final Throwable cause) { super(cause); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index 89d476a3b..58542f07d 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008-2009 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,19 +33,38 @@ package javax.media.nativewindow; -import java.lang.reflect.Constructor; +import java.io.File; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; +import javax.media.nativewindow.util.PointImmutable; + +import jogamp.common.os.PlatformPropsImpl; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NativeWindowFactoryImpl; +import jogamp.nativewindow.ToolkitProperties; +import jogamp.nativewindow.ResourceToolkitLock; +import jogamp.nativewindow.WrappedWindow; +import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.nativewindow.windows.GDIUtil; +import jogamp.nativewindow.x11.X11Lib; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; +import com.jogamp.nativewindow.awt.AWTGraphicsDevice; +import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; +import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsScreen; /** Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the {@link NativeWindow} interface, @@ -57,97 +76,132 @@ public abstract class NativeWindowFactory { protected static final boolean DEBUG; /** OpenKODE/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ - public static final String TYPE_EGL = "jogamp.newt.driver.kd".intern(); + public static final String TYPE_EGL = ".egl".intern(); /** Microsoft Windows type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_WINDOWS = "jogamp.newt.driver.windows".intern(); + public static final String TYPE_WINDOWS = ".windows".intern(); /** X11 type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_X11 = "jogamp.newt.driver.x11".intern(); + public static final String TYPE_X11 = ".x11".intern(); + + /** Broadcom VC IV/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_BCM_VC_IV = ".bcm.vc.iv".intern(); /** Android/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ - public static final String TYPE_ANDROID = "jogamp.newt.driver.android".intern(); + public static final String TYPE_ANDROID = ".android".intern(); /** Mac OS X type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_MACOSX = "jogamp.newt.driver.macosx".intern(); + public static final String TYPE_MACOSX = ".macosx".intern(); /** Generic AWT type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_AWT = "jogamp.newt.driver.awt".intern(); + public static final String TYPE_AWT = ".awt".intern(); /** Generic DEFAULT type, where platform implementation don't care, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ - public static final String TYPE_DEFAULT = "default".intern(); + public static final String TYPE_DEFAULT = ".default".intern(); private static final String nativeWindowingTypePure; // canonical String via String.intern() private static final String nativeWindowingTypeCustom; // canonical String via String.intern() - + private static NativeWindowFactory defaultFactory; private static Map<Class<?>, NativeWindowFactory> registeredFactories; - + private static Class<?> nativeWindowClass; private static boolean isAWTAvailable; - + private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; + /** {@link jogamp.nativewindow.x11.X11Util} implements {@link ToolkitProperties}. */ private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; + /** {@link jogamp.nativewindow.macosx.OSXUtil} implements {@link ToolkitProperties}. */ private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; + /** {@link jogamp.nativewindow.windows.GDIUtil} implements {@link ToolkitProperties}. */ private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; - + private static ToolkitLock jawtUtilJAWTToolkitLock; - - public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; - public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; - - private static Class<?> x11JAWTToolkitLockClass; - private static Constructor<?> x11JAWTToolkitLockConstructor; - private static Class<?> x11ToolkitLockClass; - private static Constructor<?> x11ToolkitLockConstructor; + private static boolean requiresToolkitLock; + private static boolean desktopHasThreadingIssues; + // Shutdown hook mechanism for the factory private static volatile boolean isJVMShuttingDown = false; - + private static final List<Runnable> customShutdownHooks = new ArrayList<Runnable>(); + /** Creates a new NativeWindowFactory instance. End users do not need to call this method. */ protected NativeWindowFactory() { } + private static final boolean guessBroadcomVCIV() { + return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { + private final File vcliblocation = new File( + "/opt/vc/lib/libbcm_host.so"); + @Override + public Boolean run() { + if ( vcliblocation.isFile() ) { + return Boolean.TRUE; + } + return Boolean.FALSE; + } + } ).booleanValue(); + } + private static String _getNativeWindowingType() { - switch(Platform.OS_TYPE) { + switch(PlatformPropsImpl.OS_TYPE) { case ANDROID: return TYPE_ANDROID; case MACOS: return TYPE_MACOSX; case WINDOWS: - return TYPE_WINDOWS; + return TYPE_WINDOWS; case OPENKODE: return TYPE_EGL; - + case LINUX: case FREEBSD: case SUNOS: case HPUX: default: + if( guessBroadcomVCIV() ) { + return TYPE_BCM_VC_IV; + } return TYPE_X11; } } static { - Platform.initSingleton(); - DEBUG = Debug.debug("NativeWindow"); + final boolean[] _DEBUG = new boolean[] { false }; + final String[] _tmp = new String[] { null }; + + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + Platform.initSingleton(); // last resort .. + _DEBUG[0] = Debug.debug("NativeWindow"); + _tmp[0] = PropertyAccess.getProperty("nativewindow.ws.name", true); + Runtime.getRuntime().addShutdownHook( + new Thread(new Runnable() { + @Override + public void run() { + NativeWindowFactory.shutdown(true); + } }, "NativeWindowFactory_ShutdownHook" ) ) ; + return null; + } } ) ; + + DEBUG = _DEBUG[0]; if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - Info: NativeWindowFactory.<init>"); // Thread.dumpStack(); } - + // Gather the windowing TK first nativeWindowingTypePure = _getNativeWindowingType(); - final String tmp = Debug.getProperty("nativewindow.ws.name", true); - if(null==tmp || tmp.length()==0) { + if(null==_tmp[0] || _tmp[0].length()==0) { nativeWindowingTypeCustom = nativeWindowingTypePure; } else { - nativeWindowingTypeCustom = tmp.intern(); // canonical representation + nativeWindowingTypeCustom = _tmp[0].intern(); // canonical representation } } - static boolean initialized = false; + private static boolean initialized = false; private static void initSingletonNativeImpl(final ClassLoader cl) { final String clazzName; @@ -162,12 +216,81 @@ public abstract class NativeWindowFactory { } if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "initSingleton", null, null, cl ); - - final Boolean res = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl); - requiresToolkitLock = res.booleanValue(); - } else { + + final Boolean res1 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl); + requiresToolkitLock = res1.booleanValue(); + final Boolean res2 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "hasThreadingIssues", null, null, cl); + desktopHasThreadingIssues = res2.booleanValue(); + } else { requiresToolkitLock = false; - } + desktopHasThreadingIssues = false; + } + } + + /** Returns true if the JVM is shutting down, otherwise false. */ + public static final boolean isJVMShuttingDown() { return isJVMShuttingDown; } + + /** + * Add a custom shutdown hook to be performed at JVM shutdown before shutting down NativeWindowFactory instance. + * + * @param head if true add runnable at the start, otherwise at the end + * @param runnable runnable to be added. + */ + public static void addCustomShutdownHook(final boolean head, final Runnable runnable) { + synchronized( customShutdownHooks ) { + if( !customShutdownHooks.contains( runnable ) ) { + if( head ) { + customShutdownHooks.add(0, runnable); + } else { + customShutdownHooks.add( runnable ); + } + } + } + } + + /** + * Cleanup resources at JVM shutdown + */ + public static synchronized void shutdown(final boolean _isJVMShuttingDown) { + isJVMShuttingDown = _isJVMShuttingDown; + if(DEBUG) { + System.err.println("NativeWindowFactory.shutdown() START: JVM Shutdown "+isJVMShuttingDown+", on thread "+Thread.currentThread().getName()); + } + synchronized(customShutdownHooks) { + final int cshCount = customShutdownHooks.size(); + for(int i=0; i < cshCount; i++) { + try { + if( DEBUG ) { + System.err.println("NativeWindowFactory.shutdown - customShutdownHook #"+(i+1)+"/"+cshCount); + } + customShutdownHooks.get(i).run(); + } catch(final Throwable t) { + System.err.println("NativeWindowFactory.shutdown: Caught "+t.getClass().getName()+" during customShutdownHook #"+(i+1)+"/"+cshCount); + if( DEBUG ) { + t.printStackTrace(); + } + } + } + customShutdownHooks.clear(); + } + if(DEBUG) { + System.err.println("NativeWindowFactory.shutdown(): Post customShutdownHook"); + } + + if(initialized) { + initialized = false; + if(null != registeredFactories) { + registeredFactories.clear(); + registeredFactories = null; + } + GraphicsConfigurationFactory.shutdown(); + } + + shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown + // SharedResourceToolkitLock.shutdown(DEBUG); // not used yet + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown); + } } private static void shutdownNativeImpl(final ClassLoader cl) { @@ -183,9 +306,12 @@ public abstract class NativeWindowFactory { } if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "shutdown", null, null, cl ); - } + } } - + + /** Returns true if {@link #initSingleton()} has been called w/o subsequent {@link #shutdown(boolean)}. */ + public static synchronized boolean isInitialized() { return initialized; } + /** * Static one time initialization of this factory.<br> * This initialization method <b>must be called</b> once by the program or utilizing modules! @@ -204,19 +330,20 @@ public abstract class NativeWindowFactory { if( Platform.AWT_AVAILABLE && ReflectionUtil.isClassAvailable("com.jogamp.nativewindow.awt.AWTGraphicsDevice", cl) ) { - - Method[] jawtUtilMethods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { + + final Method[] jawtUtilMethods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { + @Override public Method[] run() { try { - Class<?> _jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader()); - Method jawtUtilIsHeadlessMethod = _jawtUtilClass.getDeclaredMethod("isHeadlessMode", (Class[])null); + final Class<?> _jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader()); + final Method jawtUtilIsHeadlessMethod = _jawtUtilClass.getDeclaredMethod("isHeadlessMode", (Class[])null); jawtUtilIsHeadlessMethod.setAccessible(true); - Method jawtUtilInitMethod = _jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null); + final Method jawtUtilInitMethod = _jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null); jawtUtilInitMethod.setAccessible(true); - Method jawtUtilGetJAWTToolkitLockMethod = _jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); + final Method jawtUtilGetJAWTToolkitLockMethod = _jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); jawtUtilGetJAWTToolkitLockMethod.setAccessible(true); - return new Method[] { jawtUtilInitMethod, jawtUtilIsHeadlessMethod, jawtUtilGetJAWTToolkitLockMethod }; - } catch (Exception e) { + return new Method[] { jawtUtilInitMethod, jawtUtilIsHeadlessMethod, jawtUtilGetJAWTToolkitLockMethod }; + } catch (final Exception e) { if(DEBUG) { e.printStackTrace(); } @@ -228,7 +355,7 @@ public abstract class NativeWindowFactory { final Method jawtUtilInitMethod = jawtUtilMethods[0]; final Method jawtUtilIsHeadlessMethod = jawtUtilMethods[1]; final Method jawtUtilGetJAWTToolkitLockMethod = jawtUtilMethods[2]; - + ReflectionUtil.callMethod(null, jawtUtilInitMethod); Object resO = ReflectionUtil.callMethod(null, jawtUtilIsHeadlessMethod); @@ -239,93 +366,61 @@ public abstract class NativeWindowFactory { } else { throw new RuntimeException("JAWTUtil.isHeadlessMode() didn't return a Boolean"); } - resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitLockMethod); + resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitLockMethod); if(resO instanceof ToolkitLock) { jawtUtilJAWTToolkitLock = (ToolkitLock) resO; } else { throw new RuntimeException("JAWTUtil.getJAWTToolkitLock() didn't return a ToolkitLock"); - } + } } } - + // X11 initialization after possible AWT initialization // This is performed post AWT initialization, allowing AWT to complete the same, - // which may have been triggered before NativeWindow initialization. - // This way behavior is more uniforms across configurations (Applet/RCP, applications, ..). + // which may have been triggered before NativeWindow initialization. + // This way behavior is more uniforms across configurations (Applet/RCP, applications, ..). initSingletonNativeImpl(cl); - + registeredFactories = Collections.synchronizedMap(new HashMap<Class<?>, NativeWindowFactory>()); // register our default factory -> NativeWindow - NativeWindowFactory factory = new NativeWindowFactoryImpl(); + final NativeWindowFactory factory = new NativeWindowFactoryImpl(); nativeWindowClass = javax.media.nativewindow.NativeWindow.class; registerFactory(nativeWindowClass, factory); defaultFactory = factory; - + if ( isAWTAvailable ) { // register either our default factory or (if exist) the X11/AWT one -> AWT Component registerFactory(ReflectionUtil.getClass(ReflectionUtil.AWTNames.ComponentClass, false, cl), factory); } - if( TYPE_X11 == nativeWindowingTypePure ) { - // passing through RuntimeException if not exists intended - x11ToolkitLockClass = ReflectionUtil.getClass(X11ToolkitLockClassName, false, cl); - x11ToolkitLockConstructor = ReflectionUtil.getConstructor(x11ToolkitLockClass, new Class[] { long.class } ); - if( isAWTAvailable() ) { - x11JAWTToolkitLockClass = ReflectionUtil.getClass(X11JAWTToolkitLockClassName, false, cl); - x11JAWTToolkitLockConstructor = ReflectionUtil.getConstructor(x11JAWTToolkitLockClass, new Class[] { long.class } ); - } - } - if(DEBUG) { - System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock); + System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock+", desktopHasThreadingIssues "+desktopHasThreadingIssues); System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory); } - + GraphicsConfigurationFactory.initSingleton(); } } - public static synchronized void shutdown(boolean _isJVMShuttingDown) { - isJVMShuttingDown = _isJVMShuttingDown; - if(DEBUG) { - System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() START: JVM Shutdown "+isJVMShuttingDown); - } - if(initialized) { - initialized = false; - if(null != registeredFactories) { - registeredFactories.clear(); - registeredFactories = null; - } - GraphicsConfigurationFactory.shutdown(); - } - shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown - if(DEBUG) { - System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown); - } - } - - /** Returns true if the JVM is shutting down, otherwise false. */ - public static final boolean isJVMShuttingDown() { return isJVMShuttingDown; } - /** @return true if the underlying toolkit requires locking, otherwise false. */ public static boolean requiresToolkitLock() { return requiresToolkitLock; - } - + } + /** @return true if not headless, AWT Component and NativeWindow's AWT part available */ public static boolean isAWTAvailable() { return isAWTAvailable; } /** * @param useCustom if false return the native value, if true return a custom value if set, otherwise fallback to the native value. - * @return the native window type, e.g. {@link #TYPE_X11}, which is canonical via {@link String#intern()}. + * @return the native window type, e.g. {@link #TYPE_X11}, which is canonical via {@link String#intern()}. * Hence {@link String#equals(Object)} and <code>==</code> produce the same result. */ - public static String getNativeWindowType(boolean useCustom) { + public static String getNativeWindowType(final boolean useCustom) { return useCustom?nativeWindowingTypeCustom:nativeWindowingTypePure; } - /** Don't know if we shall add this factory here .. + /** Don't know if we shall add this factory here .. public static AbstractGraphicsDevice createGraphicsDevice(String type, String connection, int unitID, long handle, ToolkitLock locker) { if(TYPE_EGL == type) { return new @@ -338,7 +433,7 @@ public abstract class NativeWindowFactory { } */ /** Sets the default NativeWindowFactory. */ - public static void setDefaultFactory(NativeWindowFactory factory) { + public static void setDefaultFactory(final NativeWindowFactory factory) { defaultFactory = factory; } @@ -348,139 +443,102 @@ public abstract class NativeWindowFactory { } /** - * Provides the system default {@link ToolkitLock}, a singleton instance. - * <br> + * Returns the AWT {@link ToolkitLock} (JAWT based) if {@link #isAWTAvailable}, otherwise null. + * <p> + * The JAWT based {@link ToolkitLock} also locks the global lock, + * which matters if the latter is required. + * </p> + */ + public static ToolkitLock getAWTToolkitLock() { + return jawtUtilJAWTToolkitLock; + } + + public static ToolkitLock getNullToolkitLock() { + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + /** + * Provides the system default {@link ToolkitLock} for the default system windowing type. + * @see #getNativeWindowType(boolean) * @see #getDefaultToolkitLock(java.lang.String) */ public static ToolkitLock getDefaultToolkitLock() { - return getDefaultToolkitLock(getNativeWindowType(false)); + return getDefaultToolkitLock(nativeWindowingTypePure); } /** - * Provides the default {@link ToolkitLock} for <code>type</code>, a singleton instance. - * <br> + * Provides the default {@link ToolkitLock} for <code>type</code>. * <ul> - * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> - * <ul> - * <li>If <b>AWT-type</b> and <b>native-X11-type</b> and <b>AWT-available</b></li> - * <ul> - * <li> return {@link #getAWTToolkitLock()} </li> - * </ul> - * </ul> - * <li> Otherwise return {@link #getNullToolkitLock()} </li> + * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li> + * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ - public static ToolkitLock getDefaultToolkitLock(String type) { - if( requiresToolkitLock() ) { - if( TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) && isAWTAvailable() ) { + public static ToolkitLock getDefaultToolkitLock(final String type) { + if( requiresToolkitLock ) { + if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()! return getAWTToolkitLock(); } + return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } - /** Returns the AWT Toolkit (JAWT based) if {@link #isAWTAvailable}, otherwise null. */ - public static ToolkitLock getAWTToolkitLock() { - return jawtUtilJAWTToolkitLock; - } - - public static ToolkitLock getNullToolkitLock() { - return NativeWindowFactoryImpl.getNullToolkitLock(); - } - /** - * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. - * <br> + * Provides the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. * <ul> - * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> - * <ul> - * <li>If <b>X11 type</b> </li> - * <ul> - * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> - * </ul> - * </ul> - * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> + * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li> + * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ - public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { - if( requiresToolkitLock() ) { - if( TYPE_X11 == type ) { - if( 0== deviceHandle ) { - throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); - } - return createX11ToolkitLock(deviceHandle); + public static ToolkitLock getDefaultToolkitLock(final String type, final long deviceHandle) { + if( requiresToolkitLock ) { + if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()! + return getAWTToolkitLock(); } + return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } - + /** - * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. - * <br> - * <ul> - * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> - * <ul> - * <li>If <b>X11 type</b> </li> - * <ul> - * <li> If <b>shared-AWT-type</b> and <b>AWT available</b> </li> - * <ul> - * <li> return {@link jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock} </li> - * </ul> - * <li> else return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> - * </ul> - * </ul> - * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> - * </ul> + * @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 newly created AbstractGraphicsScreen matching device's native type */ - public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) { - if( requiresToolkitLock() ) { - if( TYPE_X11 == type ) { - if( 0== deviceHandle ) { - throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); - } - if( TYPE_AWT == sharedType && isAWTAvailable() ) { - return createX11AWTToolkitLock(deviceHandle); - } - return createX11ToolkitLock(deviceHandle); + public static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen) { + final String type = device.getType(); + if( TYPE_X11 == type ) { + final X11GraphicsDevice x11Device = (X11GraphicsDevice)device; + if(0 > screen) { + screen = x11Device.getDefaultScreen(); } + return new X11GraphicsScreen(x11Device, screen); } - return NativeWindowFactoryImpl.getNullToolkitLock(); - } - - protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) { - try { - if(DEBUG) { - System.err.println("NativeWindowFactory.createX11AWTToolkitLock(0x"+Long.toHexString(deviceHandle)+")"); - // Thread.dumpStack(); - } - return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); - } catch (Exception ex) { - throw new RuntimeException(ex); + if(0 > screen) { + screen = 0; // FIXME: Needs native API utilization } - } - - protected static ToolkitLock createX11ToolkitLock(long deviceHandle) { - try { - return (ToolkitLock) x11ToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); - } catch (Exception ex) { - throw new RuntimeException(ex); + if( TYPE_AWT == type ) { + final AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) device; + return new AWTGraphicsScreen(awtDevice); } + return new DefaultGraphicsScreen(device, screen); } - /** Returns the appropriate NativeWindowFactory to handle window objects of the given type. The windowClass might be {@link NativeWindow NativeWindow}, in which case the client has already assumed the responsibility of creating a compatible NativeWindow implementation, or it might be that of a toolkit class like {@link java.awt.Component Component}. */ - public static NativeWindowFactory getFactory(Class<?> windowClass) throws IllegalArgumentException { + public static NativeWindowFactory getFactory(final Class<?> windowClass) throws IllegalArgumentException { if (nativeWindowClass.isAssignableFrom(windowClass)) { return registeredFactories.get(nativeWindowClass); } Class<?> clazz = windowClass; while (clazz != null) { - NativeWindowFactory factory = registeredFactories.get(clazz); + final NativeWindowFactory factory = registeredFactories.get(clazz); if (factory != null) { return factory; } @@ -492,7 +550,7 @@ public abstract class NativeWindowFactory { /** Registers a NativeWindowFactory handling window objects of the given class. This does not need to be called by end users, only implementors of new NativeWindowFactory subclasses. */ - protected static void registerFactory(Class<?> windowClass, NativeWindowFactory factory) { + protected static void registerFactory(final Class<?> windowClass, final NativeWindowFactory factory) { if(DEBUG) { System.err.println("NativeWindowFactory.registerFactory() "+windowClass+" -> "+factory); } @@ -500,7 +558,7 @@ public abstract class NativeWindowFactory { } /** Converts the given window object and it's - {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration} into a + {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration} into a {@link NativeWindow NativeWindow} which can be operated upon by a custom toolkit, e.g. {@link javax.media.opengl.GLDrawableFactory javax.media.opengl.GLDrawableFactory}.<br> The object may be a component for a particular window toolkit, such as an AWT @@ -511,14 +569,14 @@ public abstract class NativeWindowFactory { NativeWindowFactory is responsible for handling objects from a particular window toolkit. The built-in NativeWindowFactory handles NativeWindow instances as well as AWT Components.<br> - + @throws IllegalArgumentException if the given window object could not be handled by any of the registered NativeWindowFactory instances @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ - public static NativeWindow getNativeWindow(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException, NativeWindowException { + public static NativeWindow getNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config) throws IllegalArgumentException, NativeWindowException { if (winObj == null) { throw new IllegalArgumentException("Null window object"); } @@ -530,22 +588,22 @@ public abstract class NativeWindowFactory { NativeWindow. Implementors of concrete NativeWindowFactory subclasses should override this method. */ protected abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException; - + /** * Returns the {@link OffscreenLayerSurface} instance of this {@link NativeSurface}. * <p> - * In case this surface is a {@link NativeWindow}, we traverse from the given surface + * In case this surface is a {@link NativeWindow}, we traverse from the given surface * up to root until an implementation of {@link OffscreenLayerSurface} is found. * In case <code>ifEnabled</code> is true, the surface must also implement {@link OffscreenLayerOption} - * where {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()} is <code>true</code>. + * where {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()} is <code>true</code>. * </p> - * + * * @param surface The surface to query. - * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()}. + * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()}. * @return */ - public static OffscreenLayerSurface getOffscreenLayerSurface(NativeSurface surface, boolean ifEnabled) { - if(surface instanceof OffscreenLayerSurface && + public static OffscreenLayerSurface getOffscreenLayerSurface(final NativeSurface surface, final boolean ifEnabled) { + if(surface instanceof OffscreenLayerSurface && ( !ifEnabled || surface instanceof OffscreenLayerOption ) ) { final OffscreenLayerSurface ols = (OffscreenLayerSurface) surface; return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; @@ -558,12 +616,12 @@ public abstract class NativeWindowFactory { final OffscreenLayerSurface ols = (OffscreenLayerSurface) nw; return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; } - nw = nw.getParent(); + nw = nw.getParent(); } } - return null; + return null; } - + /** * Returns true if the given visualID is valid for further processing, i.e. OpenGL usage, * otherwise return false. @@ -575,9 +633,84 @@ public abstract class NativeWindowFactory { * at creation time (see above), it is not valid for further processing. * </p> */ - public static boolean isNativeVisualIDValidForProcessing(int visualID) { - return NativeWindowFactory.TYPE_X11 != NativeWindowFactory.getNativeWindowType(false) || + public static boolean isNativeVisualIDValidForProcessing(final int visualID) { + return NativeWindowFactory.TYPE_X11 != NativeWindowFactory.getNativeWindowType(false) || VisualIDHolder.VID_UNDEFINED != visualID ; } - + + /** + * Creates a native device type, following {@link #getNativeWindowType(boolean) getNativeWindowType(true)}. + * <p> + * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired. + * </p> + */ + public static AbstractGraphicsDevice createDevice(final String displayConnection, final boolean own) { + final String nwt = NativeWindowFactory.getNativeWindowType(true); + if( NativeWindowFactory.TYPE_X11 == nwt ) { + if( own ) { + return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT, null /* ToolkitLock */); + } else { + return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT); + } + } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + /** + * FIXME: Needs service provider interface (SPI) for TK dependent implementation + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_ANDROID== nwt ) { + } else if( NativeWindowFactory.TYPE_EGL == nwt ) { + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_AWT == nwt ) { + */ + } + throw new UnsupportedOperationException("n/a for windowing system: "+nwt); + } + + /** + * Creates a wrapped {@link NativeWindow} with given native handles and {@link AbstractGraphicsScreen}. + * <p> + * The given {@link UpstreamWindowHookMutableSizePos} maybe used to reflect resizes and repositioning of the native window. + * </p> + * <p> + * The {@link AbstractGraphicsScreen} may be created via {@link #createScreen(AbstractGraphicsDevice, int)}. + * </p> + * <p> + * The {@link AbstractGraphicsScreen} may have an underlying open {@link AbstractGraphicsDevice} + * or a simple <i>dummy</i> instance, see {@link #createDevice(String, boolean)}. + * </p> + */ + public static NativeWindow createWrappedWindow(final AbstractGraphicsScreen aScreen, final long surfaceHandle, final long windowHandle, + final UpstreamWindowHookMutableSizePos hook) { + final CapabilitiesImmutable caps = new Capabilities(); + final AbstractGraphicsConfiguration config = new DefaultGraphicsConfiguration(aScreen, caps, caps); + return new WrappedWindow(config, surfaceHandle, hook, true, windowHandle); + } + + /** + * @param nw + * @return top-left client-area position in window units + */ + public static PointImmutable getLocationOnScreen(final NativeWindow nw) { + final String nwt = NativeWindowFactory.getNativeWindowType(true); + if( NativeWindowFactory.TYPE_X11 == nwt ) { + return X11Lib.GetRelativeLocation(nw.getDisplayHandle(), nw.getScreenIndex(), nw.getWindowHandle(), 0, 0, 0); + } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + return GDIUtil.GetRelativeLocation(nw.getWindowHandle(), 0, 0, 0); + } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + return OSXUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0); + /** + * FIXME: Needs service provider interface (SPI) for TK dependent implementation + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_ANDROID== nwt ) { + } else if( NativeWindowFactory.TYPE_EGL == nwt ) { + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_AWT == nwt ) { + */ + } + throw new UnsupportedOperationException("n/a for windowing system: "+nwt); + } + + } diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java index 12d30b3cd..11496899a 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java @@ -32,30 +32,30 @@ package javax.media.nativewindow; * within the implementation. */ public interface OffscreenLayerOption { - /** + /** * Request an offscreen layer, if supported. * <p> * Shall be called before the first {@link NativeWindow#lockSurface()}, * and hence before realization. * </p> - * + * * @see #getShallUseOffscreenLayer() - * @see #isOffscreenLayerSurfaceEnabled() + * @see #isOffscreenLayerSurfaceEnabled() */ public void setShallUseOffscreenLayer(boolean v); /** Returns the property set by {@link #setShallUseOffscreenLayer(boolean)}. */ public boolean getShallUseOffscreenLayer(); - /** + /** * Returns true if this instance uses an offscreen layer, otherwise false. * <p> * This instance is an offscreen layer, if {@link #setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)} * has been called before it's realization and first lock and the underlying implementation supports it. * </p> * The return value is undefined before issuing the first {@link NativeWindow#lockSurface()}. - * - * @see #setShallUseOffscreenLayer(boolean) + * + * @see #setShallUseOffscreenLayer(boolean) */ public boolean isOffscreenLayerSurfaceEnabled(); }
\ No newline at end of file diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java index f9800109c..cf8cf89d2 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -27,30 +27,60 @@ */ package javax.media.nativewindow; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PointImmutable; + +import com.jogamp.common.util.locks.RecursiveLock; + /** * Interface specifying the offscreen layer surface protocol. */ public interface OffscreenLayerSurface { - /** + /** * Attach the offscreen layer to this offscreen layer surface. + * <p> + * Implementation may realize all required resources at this point. + * </p> + * * @see #isOffscreenLayerSurfaceEnabled() * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false */ public void attachSurfaceLayer(final long layerHandle) throws NativeWindowException; - - /** + + /** * Detaches a previously attached offscreen layer from this offscreen layer surface. * @see #attachSurfaceLayer(long) * @see #isOffscreenLayerSurfaceEnabled() - * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false * or no surface layer is attached. */ public void detachSurfaceLayer() throws NativeWindowException; - + + /** Returns the attached surface layer or null if none is attached. */ + public long getAttachedSurfaceLayer(); + /** Returns true if a surface layer is attached, otherwise false. */ public boolean isSurfaceLayerAttached(); - + /** Sets the capabilities of this instance, allowing upstream API's to refine it, i.e. OpenGL related settings. */ public void setChosenCapabilities(CapabilitiesImmutable caps); - + + /** Returns the recursive lock object of this surface, which synchronizes multithreaded access. */ + public RecursiveLock getLock(); + + /** + * Optional method setting cursor in the corresponding on-screen surface/window, if exists. + * + * @param pixelrect cursor pixels, maybe null for default cursor + * @param hotSpot maybe null for default cursor + * @return true if successful, i.e. on-screen surface/window w/ cursor capabilities exists. Otherwise false. + */ + public boolean setCursor(PixelRectangle pixelrect, PointImmutable hotSpot); + + /** + * Optional method hiding the cursor in the corresponding on-screen surface/window, if exists. + * + * @return true if successful, i.e. on-screen surface/window w/ cursor capabilities exists. Otherwise false. + */ + public boolean hideCursor(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java index 395fdc818..7a69b9a40 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java @@ -33,78 +33,95 @@ import jogamp.nativewindow.Debug; /** * Provides a mutable {@link NativeSurface}, i.e. {@link MutableSurface}, while allowing an * {@link UpstreamSurfaceHook} to influence the lifecycle and information. - * + * * @see UpstreamSurfaceHook * @see MutableSurface * @see NativeSurface */ -public interface ProxySurface extends MutableSurface { +public interface ProxySurface extends MutableSurface { public static final boolean DEBUG = Debug.debug("ProxySurface"); - - /** + + /** * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's surface handle * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) * @see #getUpstreamOptionBits() - */ + */ public static final int OPT_PROXY_OWNS_UPSTREAM_SURFACE = 1 << 6; - - /** + + /** * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's {@link AbstractGraphicsDevice}. * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) * @see #getUpstreamOptionBits() - */ + */ public static final int OPT_PROXY_OWNS_UPSTREAM_DEVICE = 1 << 7; - - /** + + /** * Implementation specific bitvalue stating the upstream's {@link NativeSurface} is an invisible window, i.e. maybe incomplete. * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) * @see #getUpstreamOptionBits() - */ + */ public static final int OPT_UPSTREAM_WINDOW_INVISIBLE = 1 << 8; /** Allow redefining the AbstractGraphicsConfiguration */ - public void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg); + public void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg); + + /** + * Returns the optional upstream {@link NativeSurface} if used by implementation, otherwise <code>null</code>. + * <p> + * The upstream {@link NativeSurface} is retrieved via {@link #getUpstreamSurfaceHook() the UpstreamSurfaceHook}, + * i.e. {@link UpstreamSurfaceHook#getUpstreamSurface()}. + * </p> + * <p> + * One example is the JOGL EGLWrappedSurface, which might be backed up by a + * native platform NativeSurface (X11, WGL, CGL, ..). + * </p> + */ + public NativeSurface getUpstreamSurface(); - /** Returns the set {@link UpstreamSurfaceHook}, or null if not set. */ + /** Returns the {@link UpstreamSurfaceHook} if {@link #setUpstreamSurfaceHook(UpstreamSurfaceHook) set}, otherwise <code>null</code>. */ public UpstreamSurfaceHook getUpstreamSurfaceHook(); - + /** - * Sets the {@link UpstreamSurfaceHook} and returns the previous value. + * Overrides the {@link UpstreamSurfaceHook}. */ public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook); - - /** - * Enables or disables the {@link UpstreamSurfaceHook} lifecycle functions + + /** + * Enables or disables the {@link UpstreamSurfaceHook} lifecycle functions * {@link UpstreamSurfaceHook#create(ProxySurface)} and {@link UpstreamSurfaceHook#destroy(ProxySurface)}. * <p> * Use this for small code blocks where the native resources shall not change, * i.e. resizing a derived (OpenGL) drawable. - * </p> + * </p> */ public void enableUpstreamSurfaceHookLifecycle(boolean enable); - - /** + + /** * {@link UpstreamSurfaceHook#create(ProxySurface)} is being issued and the proxy surface/window handles shall be set. - */ + */ public void createNotify(); - - /** + + /** * {@link UpstreamSurfaceHook#destroy(ProxySurface)} is being issued and all proxy surface/window handles shall be cleared. - */ + */ public void destroyNotify(); - + public StringBuilder getUpstreamOptionBits(StringBuilder sink); public int getUpstreamOptionBits(); - + /** Returns <code>true</code> if the give bit-mask <code>v</code> is set in this instance upstream-option-bits, otherwise <code>false</code>.*/ public boolean containsUpstreamOptionBits(int v); - + /** Add the given bit-mask to this instance upstream-option-bits using bit-or w/ <code>v</code>.*/ public void addUpstreamOptionBits(int v); - + /** Clear the given bit-mask from this instance upstream-option-bits using bit-and w/ <code>~v</code>*/ public void clearUpstreamOptionBits(int v); - + public StringBuilder toString(StringBuilder sink); + @Override public String toString(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java new file mode 100644 index 000000000..ffd5c224c --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/ScalableSurface.java @@ -0,0 +1,97 @@ +/** + * Copyright 2014 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 javax.media.nativewindow; + +/** + * Adding mutable surface pixel scale property to implementing class, usually to a {@link NativeSurface} implementation, + * see {@link #setSurfaceScale(int[])}. + */ +public interface ScalableSurface { + /** Setting surface-pixel-scale of {@value}, results in same pixel- and window-units. */ + public static final int IDENTITY_PIXELSCALE = 1; + /** Setting surface-pixel-scale of {@value}, results in maximum platform dependent pixel-scale, i.e. pixel-units >> window-units where available. */ + public static final int AUTOMAX_PIXELSCALE = 0; + + /** + * Request a pixel scale in x- and y-direction for the associated {@link NativeSurface}. + * <p> + * Default pixel scale request for both directions is {@link #AUTOMAX_PIXELSCALE}. + * </p> + * <p> + * In case platform only supports uniform pixel scale, i.e. one scale for both directions, + * either {@link #AUTOMAX_PIXELSCALE} or the maximum requested pixel scale component is used. + * </p> + * <p> + * The <i>requested</i> pixel scale will be validated against platform limits before native scale-setup, + * i.e. clipped to {@link #IDENTITY_PIXELSCALE} if not supported or clipped to the platform maximum. + * It can be queried via {@link #getRequestedSurfaceScale(int[])}. + * </p> + * <p> + * The actual <i>realized</i> pixel scale values of the {@link NativeSurface} + * can be queried via {@link #getCurrentSurfaceScale(int[])} or + * computed via <code>surface.{@link NativeSurface#convertToPixelUnits(int[]) convertToPixelUnits}(new int[] { 1, 1 })</code> + * </p> + * @param pixelScale <i>requested</i> surface pixel scale int[2] values for x- and y-direction. + */ + public void setSurfaceScale(final int[] pixelScale); + + /** + * Returns the requested pixel scale of the associated {@link NativeSurface}. + * + * @param result int[2] storage for the result + * @return the passed storage containing the requested pixelScale for chaining + */ + int[] getRequestedSurfaceScale(final int[] result); + + /** + * Returns the current pixel scale of the associated {@link NativeSurface}. + * + * @param result int[2] storage for the result + * @return the passed storage containing the current pixelScale for chaining + */ + public int[] getCurrentSurfaceScale(final int[] result); + + /** + * Returns the native pixel scale of the associated {@link NativeSurface} + * reflecting it's currently bound <i>monitor surface resolution in pixels</i>. + * <p> + * The native pixel scale maybe used to determine the proper <i>dpi</i> + * value of this {@link NativeSurface}: + * <pre> + * surfacePpMM = monitorPpMM * currentSurfaceScale / nativeSurfaceScale, + * with PpMM == pixel per millimeter + * </pre> + * </p> + * + * @param result int[2] storage for the result + * @return the passed storage containing the native pixelScale for chaining + */ + public int[] getNativeSurfaceScale(final int[] result); +} + diff --git a/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java b/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java index 0912b5afe..de65a3031 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java +++ b/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.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 @@ -29,7 +29,7 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * */ package javax.media.nativewindow; diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java index 30f9660f0..017b996d7 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java @@ -33,12 +33,46 @@ import jogamp.nativewindow.Debug; /** * Marker for a singleton global recursive blocking lock implementation, * optionally locking a native windowing toolkit as well. - * <br> - * One use case is the AWT locking on X11, see {@link jogamp.nativewindow.jawt.JAWTToolkitLock}. + * <p> + * Toolkit locks are created solely via {@link NativeWindowFactory}. + * </p> + * <p> + * One use case is the AWT locking on X11, see {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. + * </p> */ public interface ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true); + /** + * Blocking until the lock is acquired by this Thread or a timeout is reached. + * <p> + * Timeout is implementation specific, if used at all. + * </p> + * + * @throws RuntimeException in case of a timeout + */ public void lock(); + + /** + * Release the lock. + * + * @throws RuntimeException in case the lock is not acquired by this thread. + */ public void unlock(); + + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + + /** + * Dispose this instance. + * <p> + * Shall be called when instance is no more required. + * </p> + * This allows implementations sharing a lock via resources + * to decrease the reference counter. + */ + public void dispose(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java b/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java index 6fe2e5364..572649875 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java +++ b/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java @@ -28,25 +28,39 @@ package javax.media.nativewindow; -/** - * Interface allowing upstream caller to pass lifecycle actions and size info - * to a {@link ProxySurface} instance. - */ +/** + * Interface allowing upstream caller to pass lifecycle actions and size info + * to a {@link ProxySurface} instance. + */ public interface UpstreamSurfaceHook { /** called within {@link ProxySurface#createNotify()} within lock, before using surface. */ public void create(ProxySurface s); /** called within {@link ProxySurface#destroyNotify()} within lock, before clearing fields. */ public void destroy(ProxySurface s); - /** Returns the width of the upstream surface, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ - public int getWidth(ProxySurface s); - /** Returns the height of the upstream surface, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ - public int getHeight(ProxySurface s); - /** - * {@link UpstreamSurfaceHook} w/ mutable size, allowing it's {@link ProxySurface} user to resize. - */ + * Returns the optional upstream {@link NativeSurface} if used by implementation, otherwise <code>null</code>. + * <p> + * One example is the JOGL EGLWrappedSurface, which might be backed up by a + * native platform NativeSurface (X11, WGL, CGL, ..). + * </p> + */ + public NativeSurface getUpstreamSurface(); + + /** Returns the width of the upstream surface in pixels, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ + public int getSurfaceWidth(ProxySurface s); + /** Returns the height of the upstream surface in pixels, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ + public int getSurfaceHeight(ProxySurface s); + + /** + * {@link UpstreamSurfaceHook} w/ mutable size, allowing it's {@link ProxySurface} user to resize. + */ public interface MutableSize extends UpstreamSurfaceHook { - public void setSize(int width, int height); + /** + * Resizes the upstream surface. + * @param width new width in pixel units + * @param height new height in pixel units + */ + public void setSurfaceSize(int width, int height); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/VisualIDHolder.java b/src/nativewindow/classes/javax/media/nativewindow/VisualIDHolder.java index 4f3d3ff00..e337166d4 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/VisualIDHolder.java +++ b/src/nativewindow/classes/javax/media/nativewindow/VisualIDHolder.java @@ -38,7 +38,7 @@ import java.util.Comparator; * </p> */ public interface VisualIDHolder { - + public enum VIDType { // Generic Values INTRINSIC(0), NATIVE(1), @@ -47,19 +47,19 @@ public interface VisualIDHolder { // X11 Values X11_XVISUAL(20), X11_FBCONFIG(21), // Windows Values - WIN32_PFD(30); - + WIN32_PFD(30); + public final int id; - VIDType(int id){ + VIDType(final int id){ this.id = id; } - } - + } + /** * Returns the native visual ID of the given <code>type</code> * if supported, or {@link #VID_UNDEFINED} if not supported. - * <p> + * <p> * Depending on the native windowing system, <code>type</code> is handled as follows: * <ul> * <li>X11 throws NativeWindowException on <code>EGL_CONFIG</code>, <code>WIN32_PFD</code> @@ -76,7 +76,7 @@ public interface VisualIDHolder { * <li><code>X11_XVISUAL</code>: <i>X11 XVisual ID</i></li> * <li><code>X11_FBCONFIG</code>: <i>X11 FBConfig ID</i> or <code>VID_UNDEFINED</code></li> * </ul></li> - * <li>Windows/GL throws NativeWindowException on <code>EGL_CONFIG</code>, <code>X11_XVISUAL</code>, <code>X11_FBCONFIG</code> + * <li>Windows/GL throws NativeWindowException on <code>EGL_CONFIG</code>, <code>X11_XVISUAL</code>, <code>X11_FBCONFIG</code> * <ul> * <li><code>INTRINSIC</code>: <i>Win32 PIXELFORMATDESCRIPTOR ID</i></li> * <li><code>NATIVE</code>: <i>Win32 PIXELFORMATDESCRIPTOR ID</i></li> @@ -91,36 +91,37 @@ public interface VisualIDHolder { * </ul> * </p> * Note: <code>INTRINSIC</code> and <code>NATIVE</code> are always handled, - * but may result in {@link #VID_UNDEFINED}. The latter is true if - * the native value are actually undefined or the corresponding object is not + * but may result in {@link #VID_UNDEFINED}. The latter is true if + * the native value are actually undefined or the corresponding object is not * mapped to a native visual object. - * + * * @throws NativeWindowException if <code>type</code> is neither * <code>INTRINSIC</code> nor <code>NATIVE</code> - * and does not match the native implementation. + * and does not match the native implementation. */ int getVisualID(VIDType type) throws NativeWindowException ; - - /** + + /** * {@link #getVisualID(VIDType)} result indicating an undefined value, * which could be cause by an unsupported query. * <p> * We assume the const value <code>0</code> doesn't reflect a valid native visual ID * and is interpreted as <i>no value</i> on all platforms. * This is currently true for Android, X11 and Windows. - * </p> + * </p> */ static final int VID_UNDEFINED = 0; - + /** Comparing {@link VIDType#NATIVE} */ public static class VIDComparator implements Comparator<VisualIDHolder> { - private VIDType type; - - public VIDComparator(VIDType type) { + private final VIDType type; + + public VIDComparator(final VIDType type) { this.type = type; } - - public int compare(VisualIDHolder vid1, VisualIDHolder vid2) { + + @Override + public int compare(final VisualIDHolder vid1, final VisualIDHolder vid2) { final int id1 = vid1.getVisualID(type); final int id2 = vid2.getVisualID(type); @@ -131,5 +132,5 @@ public interface VisualIDHolder { } return 0; } - } + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java b/src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java index 884c916e4..8570b78da 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java +++ b/src/nativewindow/classes/javax/media/nativewindow/WindowClosingProtocol.java @@ -37,13 +37,17 @@ package javax.media.nativewindow; * this protocol default behavior {@link WindowClosingMode#DISPOSE_ON_CLOSE DISPOSE_ON_CLOSE} shall be used.</p> */ public interface WindowClosingProtocol { + + /** + * Window closing mode if triggered by toolkit close operation. + */ public enum WindowClosingMode { /** * Do nothing on native window close operation.<br> * This is the default behavior within an AWT environment. */ DO_NOTHING_ON_CLOSE, - + /** * Dispose resources on native window close operation.<br> * This is the default behavior in case no underlying toolkit defines otherwise. diff --git a/src/nativewindow/classes/javax/media/nativewindow/package.html b/src/nativewindow/classes/javax/media/nativewindow/package.html index 14730a548..3fe42bab0 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/package.html +++ b/src/nativewindow/classes/javax/media/nativewindow/package.html @@ -1,7 +1,7 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> - <title>NativeWindow Protocol Draft Public Review Specification</title> + <title>NativeWindow Specification Overview</title> </head> <body> @@ -10,7 +10,7 @@ <h3>Preface</h3> This specification, an optional set of packages, describing a <i>protocol</i> for a <i>native windowing interface</i> binding to Java(TM).<br> - Currently specified <i>native windowing systems</i> are:<br><br> + Currently specified <i>native windowing systems</i> are: <ul> <li> EGL/OpenKODE Windowing System</li> <li> X11 Windowing System</li> @@ -20,95 +20,79 @@ </ul> <br> However, any other native windowing system may be added to the implementation, - using a generic string identifier and an optional specialisation of:<br><br> + using a generic string identifier and an optional specialisation of: <ul> - <li>{@link javax.media.nativewindow.AbstractGraphicsDevice AbstractGraphicsDevice},<br> - <br> - Shall return the new string identifier with {@link javax.media.nativewindow.AbstractGraphicsDevice#getType() getType()}</li> + <li>{@link javax.media.nativewindow.AbstractGraphicsDevice AbstractGraphicsDevice}, + <p>Shall return the new string identifier with {@link javax.media.nativewindow.AbstractGraphicsDevice#getType() getType()}</p></li> <li>{@link javax.media.nativewindow.AbstractGraphicsScreen AbstractGraphicsScreen}</li> <li>{@link javax.media.nativewindow.AbstractGraphicsConfiguration AbstractGraphicsConfiguration}</li> </ul> - <br> - The implementor has to provide the following:<br><br> + <p>The implementor has to provide the following:</p> <ul> - <li> The specialisation of the abstract class {@link javax.media.nativewindow.NativeWindowFactory NativeWindowFactory}<br> - <br> - shall be registered with {@link javax.media.nativewindow.NativeWindowFactory#registerFactory NativeWindowFactory.registerFactory(..)}.</li> + <li> The specialisation of the abstract class {@link javax.media.nativewindow.NativeWindowFactory NativeWindowFactory} + <p>shall be registered with {@link javax.media.nativewindow.NativeWindowFactory#registerFactory NativeWindowFactory.registerFactory(..)}.</p></li> - <li> The specialisation of the abstract class {@link javax.media.nativewindow.GraphicsConfigurationFactory GraphicsConfigurationFactory}<br> - <br> - shall be registered with {@link javax.media.nativewindow.GraphicsConfigurationFactory#registerFactory GraphicsConfigurationFactory.registerFactory(..)}.</li> - </ul><br> - This protocol <i>does not</i> describe how to <i>create</i> native windows, but how to <i>bind</i> a native surface to an implementation of - and window to an implementation of {@link javax.media.nativewindow.NativeSurface NativeSurface}.<br> - {@link javax.media.nativewindow.NativeWindow NativeWindow} specializes the NativeSurface.<br> - However, an implementation of this protocol (e.g. {@link com.jogamp.newt}) may support the creation.<br> + <li> The specialisation of the abstract class {@link javax.media.nativewindow.GraphicsConfigurationFactory GraphicsConfigurationFactory} + <p>shall be registered with {@link javax.media.nativewindow.GraphicsConfigurationFactory#registerFactory GraphicsConfigurationFactory.registerFactory(..)}.</p></li> + </ul> + <p>This protocol <i>does not</i> describe how to <i>create</i> native windows, but how to <i>bind</i> a native surface to an implementation of + and window to an implementation of {@link javax.media.nativewindow.NativeSurface NativeSurface}.</p> + <p>{@link javax.media.nativewindow.NativeWindow NativeWindow} specializes the NativeSurface.</p> + <p>However, an implementation of this protocol (e.g. {@link com.jogamp.newt}) may support the creation.</p> <h3>Dependencies</h3> This binding has dependencies to the following: <ul> - <li> Either of the following Java implementations:<br/> + <li> Either of the following Java implementations: <ul> - <li> <a href="http://java.sun.com/j2se/1.5.0/docs/api/">Java SE 1.5 or later</a> </li> - <li> A mobile JavaVM with language 1.5 support, ie: + <li> <a href="http://docs.oracle.com/javase/6/docs/api/">Java SE 1.6 or later</a> </li> + <li> A mobile JavaVM with language 1.6 support, ie: <ul> - <li> <a href="http://developer.android.com/reference/packages.html">Dalvik API Level 7</a> </li> + <li> <a href="http://developer.android.com/reference/packages.html">Android API Level 9 (Version 2.3)</a> </li> <li> <a href="http://jamvm.sourceforge.net/">JamVM</a> </li> </ul> with <ul> - <li> <a href="http://java.sun.com/products/foundation/">Foundation Profile 1.1.2 (JSR 219)</a> </li> - <li> <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/nio/package-summary.html"> Java 1.4 <i>java.nio</i> implementation</a> </li> + <li> <a href="http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/package-summary.html"> Java 1.4 <i>java.nio</i> implementation</a> </li> </ul></li> </ul></li> </ul> <br> <h3>Package Structure</h3> - The packages defined by this specification include:<br/><br/> + The packages defined by this specification include: <ul> - <li>The <b>javax.media.nativewindow</b> package<br> - <br> - This package contains Java bindings for a native windowing system.<br> - Subsequent packages contain marker type classes, containing native characteristics of the windowing system. - - <ul> - <li>The <b>javax.media.nativewindow.awt</b> package<br> - <br> - This sub package contains classes to cover the native characteristics of the AWT windowing system.</li> + <li>The <b>javax.media.nativewindow</b> package + <p>This package contains Java bindings for a native windowing system.</p> + <p>Subsequent packages contain marker type classes, containing native characteristics of the windowing system.</p> + <ul> + <li>The <b>javax.media.nativewindow.awt</b> package + <p>This sub package contains classes to cover the native characteristics of the AWT windowing system.</p></li> - <li>The <b>javax.media.nativewindow.x11</b> package<br> - <br> - This sub package contains classes to cover the native characteristics of the X11 windowing system.</li> + <li>The <b>javax.media.nativewindow.x11</b> package + <p>This sub package contains classes to cover the native characteristics of the X11 windowing system.</p></li> - <li>The <b>javax.media.nativewindow.windows</b> package<br> - <br> - This sub package contains classes to cover the native characteristics of the Windows windowing system.</li> + <li>The <b>javax.media.nativewindow.windows</b> package + <p>This sub package contains classes to cover the native characteristics of the Windows windowing system.</p></li> - <li>The <b>javax.media.nativewindow.macosx</b> package<br> - <br> - This sub package contains classes to cover the native characteristics of the MacOSX windowing system.</li> + <li>The <b>javax.media.nativewindow.macosx</b> package + <p>This sub package contains classes to cover the native characteristics of the MacOSX windowing system.</p></li> - <li>The <b>javax.media.nativewindow.egl</b> package<br> - <br> - This sub package contains classes to cover the native characteristics of the EGL/OpenKODE windowing system.</li> + <li>The <b>javax.media.nativewindow.egl</b> package + <p>This sub package contains classes to cover the native characteristics of the EGL/OpenKODE windowing system.</p></li> </ul></li> </ul> <h3>Factory Model</h3> -Running on a platform with a supported windowing system, the factory model shall be used -to instantiate a native window, see {@link javax.media.nativewindow.NativeWindowFactory NativeWindowFactory}.<br> -The implementor has to specialize -All supported -Regardless of the knowledge of the underly -<br> +<p>Running on a platform with a supported windowing system, the factory model shall be used +to instantiate a native window, see {@link javax.media.nativewindow.NativeWindowFactory NativeWindowFactory}.</p> -<h3>Revision History<br> - </h3> +<h3>Revision History</h3> <ul> <li> Early Draft Review, June 2009</li> <li> 2.0.0 Maintenance Release, February 2011</li> +<li> 2.0.2 Major Release, July 18th 2013</li> </ul> <br> <br> diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/Dimension.java b/src/nativewindow/classes/javax/media/nativewindow/util/Dimension.java index 0a5a94565..4c9672c26 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/Dimension.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/Dimension.java @@ -4,14 +4,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 @@ -21,12 +21,12 @@ * 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 javax.media.nativewindow.util; public class Dimension implements Cloneable, DimensionImmutable { @@ -37,7 +37,11 @@ public class Dimension implements Cloneable, DimensionImmutable { this(0, 0); } - public Dimension(int width, int height) { + public Dimension(final int[] size) { + this(size[0], size[1]); + } + + public Dimension(final int width, final int height) { if(width<0 || height<0) { throw new IllegalArgumentException("width and height must be within: ["+0+".."+Integer.MAX_VALUE+"]"); } @@ -45,55 +49,79 @@ public class Dimension implements Cloneable, DimensionImmutable { this.height=height; } + @Override public Object cloneMutable() { return clone(); } - + + @Override public Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException ex) { + } catch (final CloneNotSupportedException ex) { throw new InternalError(); } } - public int getWidth() { return width; } - public int getHeight() { return height; } + @Override + public final int getWidth() { return width; } + @Override + public final int getHeight() { return height; } - public void setWidth(int width) { + public final void set(final int width, final int height) { + this.width = width; + this.height = height; + } + public final void setWidth(final int width) { this.width = width; } - public void setHeight(int height) { + public final void setHeight(final int height) { this.height = height; } - public Dimension scale(int s) { + public final Dimension scale(final int s) { width *= s; height *= s; return this; } - public Dimension add(Dimension pd) { + public final Dimension add(final Dimension pd) { width += pd.width ; height += pd.height ; return this; } + @Override public String toString() { - return new String(width+" x "+height); + return width + " x " + height; + } + + @Override + public int compareTo(final DimensionImmutable d) { + final int tsq = width*height; + final int xsq = d.getWidth()*d.getHeight(); + + if(tsq > xsq) { + return 1; + } else if(tsq < xsq) { + return -1; + } + return 0; } - public boolean equals(Object obj) { + @Override + public boolean equals(final Object obj) { if(this == obj) { return true; } if (obj instanceof Dimension) { - Dimension p = (Dimension)obj; - return height == p.height && + final Dimension p = (Dimension)obj; + return height == p.height && width == p.width ; } return false; } + @Override public int hashCode() { // 31 * x == (x << 5) - x - int hash = 31 + width; + final int hash = 31 + width; return ((hash << 5) - hash) + height; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/DimensionImmutable.java b/src/nativewindow/classes/javax/media/nativewindow/util/DimensionImmutable.java index d14e94c10..e6cacf4ff 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/DimensionImmutable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/DimensionImmutable.java @@ -37,21 +37,32 @@ import com.jogamp.common.type.WriteCloneable; * <li><code>height</code></li> * </ul> */ -public interface DimensionImmutable extends WriteCloneable { +public interface DimensionImmutable extends WriteCloneable, Comparable<DimensionImmutable> { int getHeight(); int getWidth(); /** + * <p> + * Compares square of size. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final DimensionImmutable d); + + /** * Checks whether two dimensions objects are equal. Two instances * of <code>DimensionReadOnly</code> are equal if two components * <code>height</code> and <code>width</code> are equal. * @return <code>true</code> if the two dimensions are equal; * otherwise <code>false</code>. */ + @Override boolean equals(Object obj); + @Override int hashCode(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/Insets.java b/src/nativewindow/classes/javax/media/nativewindow/util/Insets.java index 199ec27cb..5ec4c758f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/Insets.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/Insets.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,76 +20,117 @@ * 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 javax.media.nativewindow.util; +/** + * Mutable insets representing rectangular window decoration insets on all four edges + * in window units. + */ public class Insets implements Cloneable, InsetsImmutable { static final InsetsImmutable zeroInsets = new Insets(); public static final InsetsImmutable getZero() { return zeroInsets; } - - int l, r, t, b; + + private int l, r, t, b; public Insets() { this(0, 0, 0, 0); } - public Insets(int left, int right, int top, int bottom) { + public Insets(final int left, final int right, final int top, final int bottom) { this.l=left; this.r=right; this.t=top; this.b=bottom; } - + + @Override public Object cloneMutable() { return clone(); } - + + @Override protected Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException ex) { + } catch (final CloneNotSupportedException ex) { throw new InternalError(); } } + @Override public final int getLeftWidth() { return l; } + @Override public final int getRightWidth() { return r; } + @Override public final int getTotalWidth() { return l + r; } + @Override public final int getTopHeight() { return t; } + @Override public final int getBottomHeight() { return b; } + @Override public final int getTotalHeight() { return t + b; } - public void setLeftWidth(int left) { l = left; } - public void setRightWidth(int right) { r = right; } - public void setTopHeight(int top) { t = top; } - public void setBottomHeight(int bottom) { b = bottom; } - - public boolean equals(Object obj) { + /** + * Set the inset values of this instance in window units. + * @param left left inset width in window units. + * @param right right inset width in window units. + * @param top top inset width in window units. + * @param bottom bottom inset width in window units. + */ + public final void set(final int left, final int right, final int top, final int bottom) { + l = left; r = right; t = top; b = bottom; + } + /** + * Set the left inset value of this instance in window units. + * @param left left inset width in window units. + */ + public final void setLeftWidth(final int left) { l = left; } + /** + * Set the right inset value of this instance in window units. + * @param right right inset width in window units. + */ + public final void setRightWidth(final int right) { r = right; } + /** + * Set the top inset value of this instance in window units. + * @param top top inset width in window units. + */ + public final void setTopHeight(final int top) { t = top; } + /** + * Set the bottom inset value of this instance in window units. + * @param bottom bottom inset width in window units. + */ + public final void setBottomHeight(final int bottom) { b = bottom; } + + @Override + public boolean equals(final Object obj) { if(this == obj) { return true; } if (obj instanceof Insets) { - Insets insets = (Insets)obj; + final Insets insets = (Insets)obj; return (r == insets.r) && (l == insets.l) && (b == insets.b) && (t == insets.t); } return false; } + @Override public int hashCode() { - int sum1 = l + b; - int sum2 = t + r; - int val1 = sum1 * (sum1 + 1)/2 + l; - int val2 = sum2 * (sum2 + 1)/2 + r; - int sum3 = val1 + val2; + final int sum1 = l + b; + final int sum2 = t + r; + final int val1 = sum1 * (sum1 + 1)/2 + l; + final int val2 = sum2 * (sum2 + 1)/2 + r; + final int sum3 = val1 + val2; return sum3 * (sum3 + 1)/2 + val2; } + @Override public String toString() { - return new String("[ l "+l+", r "+r+" - t "+t+", b "+b+" - "+getTotalWidth()+"x"+getTotalHeight()+"]"); + return "[ l "+l+", r "+r+" - t "+t+", b "+b+" - "+getTotalWidth()+"x"+getTotalHeight()+"]"; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/InsetsImmutable.java b/src/nativewindow/classes/javax/media/nativewindow/util/InsetsImmutable.java index 075641ede..0f8ba0158 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/InsetsImmutable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/InsetsImmutable.java @@ -30,25 +30,28 @@ package javax.media.nativewindow.util; import com.jogamp.common.type.WriteCloneable; -/** Immutable Rectangle interface */ +/** + * Immutable insets representing rectangular window decoration insets on all four edges + * in window units. + */ public interface InsetsImmutable extends WriteCloneable { - /** @return left inset width */ + /** @return left inset width in window units. */ int getLeftWidth(); - /** @return right inset width */ + /** @return right inset width in window units. */ int getRightWidth(); - /** @return total width, ie. <code>left_width + right_width</code> */ + /** @return total width in window units, ie. <code>left_width + right_width</code> */ int getTotalWidth(); - - /** @return top inset height */ + + /** @return top inset height in window units. */ int getTopHeight(); - /** @return bottom inset height */ + /** @return bottom inset height in window units. */ int getBottomHeight(); - - /** @return total height, ie. <code>top_height + bottom_height</code> */ + + /** @return total height in window units, ie. <code>top_height + bottom_height</code> */ int getTotalHeight(); /** @@ -59,8 +62,10 @@ public interface InsetsImmutable extends WriteCloneable { * @return <code>true</code> if the two Insets are equal; * otherwise <code>false</code>. */ + @Override boolean equals(Object obj); + @Override int hashCode(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java new file mode 100644 index 000000000..e5901f584 --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java @@ -0,0 +1,197 @@ +/** + * Copyright (c) 2014 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 javax.media.nativewindow.util; + +/** + * Basic pixel formats + * <p> + * Notation follows OpenGL notation, i.e. + * name consist of all it's component names + * followed by their bit size. + * </p> + * <p> + * Order of component names is from lowest-bit to highest-bit. + * </p> + * <p> + * In case component-size is 1 byte (e.g. OpenGL data-type GL_UNSIGNED_BYTE), + * component names are ordered from lowest-byte to highest-byte. + * Note that OpenGL applies special interpretation if + * data-type is e.g. GL_UNSIGNED_8_8_8_8_REV or GL_UNSIGNED_8_8_8_8_REV. + * </p> + * <p> + * PixelFormat can be converted to OpenGL GLPixelAttributes + * via + * <pre> + * GLPixelAttributes glpa = GLPixelAttributes.convert(PixelFormat pixFmt, GLProfile glp); + * </pre> + * </p> + * <p> + * See OpenGL Specification 4.3 - February 14, 2013, Core Profile, + * Section 8.4.4 Transfer of Pixel Rectangles, p. 161-174. + * </ul> + * + * </p> + */ +public enum PixelFormat { + /** + * Pixel size is 1 bytes (8 bits) with one component of size 1 byte (8 bits). + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_ALPHA (< GL3), GL_RED (>= GL3), data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>none</i></li> + * </ul> + * </p> + */ + LUMINANCE(1, 8), + + /** + * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits). + * <p> + * The components are interleaved in the order: + * <ul> + * <li>Low to High: R, G, B</li> + * </ul> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + RGB888(3, 24), + + /** + * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits). + * <p> + * The components are interleaved in the order: + * <ul> + * <li>Low to High: B, G, R</li> + * </ul> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGR (>= GL2), data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_3BYTE_BGR TYPE_3BYTE_BGR}</li> + * </ul> + * </p> + */ + BGR888(3, 24), + + /** + * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * <p> + * The components are interleaved in the order: + * <ul> + * <li>Low to High: R, G, B, A</li> + * </ul> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>None</i></li> + * <li>PointerIcon: OSX (NSBitmapImageRep)</li> + * <li>Window Icon: OSX (NSBitmapImageRep)</li> + * <li>PNGJ: Scanlines</li> + * </ul> + * </p> + */ + RGBA8888(4, 32), + + /** + * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * <p> + * The components are interleaved in the order: + * <ul> + * <li>Low to High: A, B, G, R</li> + * </ul> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_8_8_8_8</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}</li> + * </ul> + * </p> + */ + ABGR8888(4, 32), + + /** + * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * <p> + * The components are interleaved in the order: + * <ul> + * <li>Low to High: A, R, G, B</li> + * </ul> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_INT_8_8_8_8</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + ARGB8888(4, 32), + + /** + * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * <p> + * The components are interleaved in the order: + * <ul> + * <li>Low to High: B, G, R, A</li> + * </ul> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_ARGB TYPE_INT_ARGB}</li> + * <li>PointerIcon: X11 (XCURSOR), Win32, AWT</li> + * <li>Window Icon: X11, Win32</li> + * </ul> + * </p> + */ + BGRA8888(4, 32); + + /** Number of components per pixel, e.g. 4 for RGBA. */ + public final int componentCount; + /** Number of bits per pixel, e.g. 32 for RGBA. */ + public final int bitsPerPixel; + /** Number of bytes per pixel, e.g. 4 for RGBA. */ + public final int bytesPerPixel() { return (7+bitsPerPixel)/8; } + + private PixelFormat(final int componentCount, final int bpp) { + this.componentCount = componentCount; + this.bitsPerPixel = bpp; + } +} diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java new file mode 100644 index 000000000..21bfa8a54 --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java @@ -0,0 +1,373 @@ +/** + * Copyright (c) 2014 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 javax.media.nativewindow.util; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import com.jogamp.common.nio.Buffers; + +/** + * Pixel Rectangle Utilities. + * <p> + * All conversion methods are endian independent. + * </p> + */ +public class PixelFormatUtil { + public static interface PixelSink { + /** Return the sink's destination pixelformat. */ + PixelFormat getPixelformat(); + + /** + * Returns stride in byte-size, i.e. byte count from one line to the next. + * <p> + * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}. + * </p> + */ + int getStride(); + + /** + * Returns <code>true</code> if the sink's memory is laid out in + * OpenGL's coordinate system, <i>origin at bottom left</i>. + * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>. + */ + boolean isGLOriented(); + } + /** + * Pixel sink for up-to 32bit. + */ + public static interface PixelSink32 extends PixelSink { + /** + * Will be invoked over all rows top-to down + * and all columns left-to-right. + * <p> + * Shall consider dest pixelformat and only store as much components + * as defined, up to 32bit. + * </p> + * <p> + * Implementation may better write single bytes from low-to-high bits, + * e.g. {@link ByteOrder#LITTLE_ENDIAN} order. + * Otherwise a possible endian conversion must be taken into consideration. + * </p> + * @param x + * @param y + * @param pixel + */ + void store(int x, int y, int pixel); + } + + /** + * Returns the {@link PixelFormat} with reversed components of <code>fmt</code>. + * If no reversed {@link PixelFormat} is available, returns <code>fmt</code>. + */ + public static PixelFormat getReversed(final PixelFormat fmt) { + switch(fmt) { + case LUMINANCE: + return PixelFormat.LUMINANCE; + case RGB888: + return PixelFormat.BGR888; + case BGR888: + return PixelFormat.RGB888; + case RGBA8888: + return PixelFormat.ABGR8888; + case ABGR8888: + return PixelFormat.RGBA8888; + case ARGB8888: + return PixelFormat.BGRA8888; + case BGRA8888: + return PixelFormat.ABGR8888; + default: + throw new InternalError("Unhandled format "+fmt); + } + } + + public static int getValue32(final PixelFormat src_fmt, final ByteBuffer src, int srcOff) { + switch(src_fmt) { + case LUMINANCE: { + final byte c1 = src.get(srcOff++); + return ( 0xff ) << 24 | ( 0xff & c1 ) << 16 | ( 0xff & c1 ) << 8 | ( 0xff & c1 ); + } + case RGB888: + case BGR888: { + final byte c1 = src.get(srcOff++); + final byte c2 = src.get(srcOff++); + final byte c3 = src.get(srcOff++); + return ( 0xff ) << 24 | ( 0xff & c3 ) << 16 | ( 0xff & c2 ) << 8 | ( 0xff & c1 ); + } + case RGBA8888: + case ABGR8888: + case ARGB8888: + case BGRA8888: { + final byte c1 = src.get(srcOff++); + final byte c2 = src.get(srcOff++); + final byte c3 = src.get(srcOff++); + final byte c4 = src.get(srcOff++); + return ( 0xff & c4 ) << 24 | ( 0xff & c3 ) << 16 | ( 0xff & c2 ) << 8 | ( 0xff & c1 ); + } + default: + throw new InternalError("Unhandled format "+src_fmt); + } + } + + public static int convertToInt32(final PixelFormat dest_fmt, final byte r, final byte g, final byte b, final byte a) { + switch(dest_fmt) { + case LUMINANCE: { + final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) ); + return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l ); + } + case RGB888: + return ( 0xff ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r ); + case BGR888: + return ( 0xff ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b ); + case RGBA8888: + return ( 0xff & a ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r ); + case ABGR8888: + return ( 0xff & r ) << 24 | ( 0xff & g ) << 16 | ( 0xff & b ) << 8 | ( 0xff & a ); + case ARGB8888: + return ( 0xff & b ) << 24 | ( 0xff & g ) << 16 | ( 0xff & r ) << 8 | ( 0xff & a ); + case BGRA8888: + return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b ); + default: + throw new InternalError("Unhandled format "+dest_fmt); + } + } + + public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) { + final byte r, g, b, a; + switch(src_fmt) { + case LUMINANCE: + r = src.get(srcOff++); // R + g = r; // G + b = r; // B + a = (byte) 0xff; // A + break; + case RGB888: + r = src.get(srcOff++); // R + g = src.get(srcOff++); // G + b = src.get(srcOff++); // B + a = (byte) 0xff; // A + break; + case BGR888: + b = src.get(srcOff++); // B + g = src.get(srcOff++); // G + r = src.get(srcOff++); // R + a = (byte) 0xff; // A + break; + case RGBA8888: + r = src.get(srcOff++); // R + g = src.get(srcOff++); // G + b = src.get(srcOff++); // B + a = src.get(srcOff++); // A + break; + case ABGR8888: + a = src.get(srcOff++); // A + b = src.get(srcOff++); // B + g = src.get(srcOff++); // G + r = src.get(srcOff++); // R + break; + case ARGB8888: + a = src.get(srcOff++); // A + r = src.get(srcOff++); // R + g = src.get(srcOff++); // G + b = src.get(srcOff++); // B + break; + case BGRA8888: + b = src.get(srcOff++); // B + g = src.get(srcOff++); // G + r = src.get(srcOff++); // R + a = src.get(srcOff++); // A + break; + default: + throw new InternalError("Unhandled format "+src_fmt); + } + return convertToInt32(dest_fmt, r, g, b, a); + } + + public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel) { + final byte r, g, b, a; + switch(src_fmt) { + case LUMINANCE: + r = (byte) ( src_pixel ); // R + g = r; // G + b = r; // B + a = (byte) 0xff; // A + break; + case RGB888: + r = (byte) ( src_pixel ); // R + g = (byte) ( src_pixel >>> 8 ); // G + b = (byte) ( src_pixel >>> 16 ); // B + a = (byte) 0xff; // A + break; + case BGR888: + b = (byte) ( src_pixel ); // B + g = (byte) ( src_pixel >>> 8 ); // G + r = (byte) ( src_pixel >>> 16 ); // R + a = (byte) 0xff; // A + break; + case RGBA8888: + r = (byte) ( src_pixel ); // R + g = (byte) ( src_pixel >>> 8 ); // G + b = (byte) ( src_pixel >>> 16 ); // B + a = (byte) ( src_pixel >>> 24 ); // A + break; + case ABGR8888: + a = (byte) ( src_pixel ); // A + b = (byte) ( src_pixel >>> 8 ); // B + g = (byte) ( src_pixel >>> 16 ); // G + r = (byte) ( src_pixel >>> 24 ); // R + break; + case ARGB8888: + a = (byte) ( src_pixel ); // A + r = (byte) ( src_pixel >>> 8 ); // R + g = (byte) ( src_pixel >>> 16 ); // G + b = (byte) ( src_pixel >>> 24 ); // B + break; + case BGRA8888: + b = (byte) ( src_pixel ); // B + g = (byte) ( src_pixel >>> 8 ); // G + r = (byte) ( src_pixel >>> 16 ); // R + a = (byte) ( src_pixel >>> 24 ); // A + break; + default: + throw new InternalError("Unhandled format "+src_fmt); + } + return convertToInt32(dest_fmt, r, g, b, a); + } + + public static PixelRectangle convert32(final PixelRectangle src, + final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented, + final boolean destIsDirect) { + final int width = src.getSize().getWidth(); + final int height = src.getSize().getHeight(); + final int bpp = destFmt.bytesPerPixel(); + final int destStride; + if( 0 != ddestStride ) { + destStride = ddestStride; + if( destStride < bpp * width ) { + throw new IllegalArgumentException("Invalid stride "+destStride+", must be greater than bytesPerPixel "+bpp+" * width "+width); + } + } else { + destStride = bpp * width; + } + final int capacity = destStride*height; + final ByteBuffer bb = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order()); + + // System.err.println("XXX: SOURCE "+src); + // System.err.println("XXX: DEST fmt "+destFmt+", stride "+destStride+" ("+ddestStride+"), isGL "+isGLOriented+", "+width+"x"+height+", capacity "+capacity+", "+bb); + + final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() { + public void store(final int x, final int y, final int pixel) { + int o = destStride*y+x*bpp; + bb.put(o++, (byte) ( pixel )); // 1 + if( 3 <= bpp ) { + bb.put(o++, (byte) ( pixel >>> 8 )); // 2 + bb.put(o++, (byte) ( pixel >>> 16 )); // 3 + if( 4 <= bpp ) { + bb.put(o++, (byte) ( pixel >>> 24 )); // 4 + } + } + } + @Override + public final PixelFormat getPixelformat() { + return destFmt; + } + @Override + public final int getStride() { + return destStride; + } + @Override + public final boolean isGLOriented() { + return isGLOriented; + } + }; + convert32(imgSink, src); + return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, bb); + } + + public static void convert32(final PixelSink32 destInt32, final PixelRectangle src) { + convert32(destInt32, + src.getPixels(), src.getPixelformat(), + src.isGLOriented(), + src.getSize().getWidth(), src.getSize().getHeight(), + src.getStride()); + } + + /** + * + * @param dest32 32bit pixel sink + * @param src_bb + * @param src_fmt + * @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, + * otherwise <i>origin at top left</i>. + * @param width + * @param height + * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next. + * If zero, stride is set to <code>width * bytes-per-pixel</code>. + * If not zero, value must be >= <code>width * bytes-per-pixel</code>. + * @param stride_bytes stride in byte-size, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat#bytesPerPixel() src_fmt.bytesPerPixel()} * width. + * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid + */ + public static void convert32(final PixelSink32 dest32, + final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, final int width, final int height, int stride_bytes) { + final int src_bpp = src_fmt.bytesPerPixel(); + if( 0 != stride_bytes ) { + if( stride_bytes < src_bpp * width ) { + throw new IllegalArgumentException("Invalid stride "+stride_bytes+", must be greater than bytesPerPixel "+src_bpp+" * width "+width); + } + } else { + stride_bytes = src_bpp * width; + } + final PixelFormat dest_fmt = dest32.getPixelformat(); + final boolean vert_flip = src_glOriented != dest32.isGLOriented(); + final boolean fast_copy = src_fmt == dest_fmt && dest_fmt.bytesPerPixel() == 4 ; + // System.err.println("XXX: SRC fmt "+src_fmt+", stride "+stride_bytes+", isGL "+src_glOriented+", "+width+"x"+height); + // System.err.println("XXX: DST fmt "+dest_fmt+", fast_copy "+fast_copy); + + if( fast_copy ) { + // Fast copy + for(int y=0; y<height; y++) { + int o = vert_flip ? ( height - 1 - y ) * stride_bytes : y * stride_bytes; + for(int x=0; x<width; x++) { + dest32.store(x, y, getValue32(src_fmt, src_bb, o)); + o += src_bpp; + } + } + } else { + // Conversion + for(int y=0; y<height; y++) { + int o = vert_flip ? ( height - 1 - y ) * stride_bytes : y * stride_bytes; + for(int x=0; x<width; x++) { + dest32.store( x, y, convertToInt32( dest_fmt, src_fmt, src_bb, o)); + o += src_bpp; + } + } + } + } +} + diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java new file mode 100644 index 000000000..96c1f7b33 --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2014 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 javax.media.nativewindow.util; + +import java.nio.ByteBuffer; + +/** + * Pixel Rectangle identified by it's {@link #hashCode()}. + * <p> + * The {@link #getPixels()} are assumed to be immutable. + * </p> + */ +public interface PixelRectangle { + /** + * <p> + * Computes a hash code over: + * <ul> + * <li>pixelformat</li> + * <li>size</li> + * <li>stride</li> + * <li>isGLOriented</li> + * <li>pixels</li> + * </ul> + * </p> + * <p> + * The hashCode shall be computed only once with first call + * and stored for later retrieval to enhance performance. + * </p> + * <p> + * {@inheritDoc} + * </p> + */ + @Override + int hashCode(); + + /** Returns the {@link PixelFormat}. */ + PixelFormat getPixelformat(); + + /** Returns the size, i.e. width and height. */ + DimensionImmutable getSize(); + + /** + * Returns stride in byte-size, i.e. byte count from one line to the next. + * <p> + * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}. + * </p> + */ + int getStride(); + + /** + * Returns <code>true</code> if the memory is laid out in + * OpenGL's coordinate system, <i>origin at bottom left</i>. + * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>. + */ + public boolean isGLOriented(); + + /** Returns the pixels. */ + ByteBuffer getPixels(); + + @Override + String toString(); + + /** + * Generic PixelRectangle implementation + */ + public static class GenericPixelRect implements PixelRectangle { + protected final PixelFormat pixelformat; + protected final DimensionImmutable size; + protected final int strideInBytes; + protected final boolean isGLOriented; + protected final ByteBuffer pixels; + private int hashCode = 0; + private volatile boolean hashCodeComputed = false; + + /** + * + * @param pixelformat + * @param size + * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next. + * If not zero, value must be >= <code>width * bytes-per-pixel</code>. + * If zero, stride is set to <code>width * bytes-per-pixel</code>. + * @param isGLOriented + * @param pixels + * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid. + * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left + */ + public GenericPixelRect(final PixelFormat pixelformat, final DimensionImmutable size, int strideInBytes, final boolean isGLOriented, final ByteBuffer pixels) + throws IllegalArgumentException, IndexOutOfBoundsException + { + if( 0 != strideInBytes ) { + if( strideInBytes < pixelformat.bytesPerPixel() * size.getWidth()) { + throw new IllegalArgumentException("Invalid stride "+strideInBytes+", must be greater than bytesPerPixel "+pixelformat.bytesPerPixel()+" * width "+size.getWidth()); + } + } else { + strideInBytes = pixelformat.bytesPerPixel() * size.getWidth(); + } + final int reqBytes = strideInBytes * size.getHeight(); + if( pixels.limit() < reqBytes ) { + throw new IndexOutOfBoundsException("Dest buffer has insufficient bytes left, needs "+reqBytes+": "+pixels); + } + this.pixelformat = pixelformat; + this.size = size; + this.strideInBytes = strideInBytes; + this.isGLOriented = isGLOriented; + this.pixels = pixels; + } + + /** + * Copy ctor validating src. + * @param src + * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid. + * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left + */ + public GenericPixelRect(final PixelRectangle src) + throws IllegalArgumentException, IndexOutOfBoundsException + { + this(src.getPixelformat(), src.getSize(), src.getStride(), src.isGLOriented(), src.getPixels()); + } + + @Override + public int hashCode() { + if( !hashCodeComputed ) { // DBL CHECKED OK VOLATILE + synchronized (this) { + if( !hashCodeComputed ) { + // 31 * x == (x << 5) - x + int hash = 31 + pixelformat.hashCode(); + hash = ((hash << 5) - hash) + size.hashCode(); + hash = ((hash << 5) - hash) + strideInBytes; + hash = ((hash << 5) - hash) + ( isGLOriented ? 1 : 0); + hashCode = ((hash << 5) - hash) + pixels.hashCode(); + hashCodeComputed = true; + } + } + } + return hashCode; + } + + @Override + public PixelFormat getPixelformat() { + return pixelformat; + } + + @Override + public DimensionImmutable getSize() { + return size; + } + + @Override + public int getStride() { + return strideInBytes; + } + + @Override + public boolean isGLOriented() { + return isGLOriented; + } + + @Override + public ByteBuffer getPixels() { + return pixels; + } + + @Override + public final String toString() { + return "PixelRect[obj 0x"+Integer.toHexString(super.hashCode())+", "+pixelformat+", "+size+", stride "+strideInBytes+", isGLOrient "+isGLOriented+", pixels "+pixels+"]"; + } + } +} + diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/Point.java b/src/nativewindow/classes/javax/media/nativewindow/util/Point.java index c53b16928..3576a7dd0 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/Point.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/Point.java @@ -33,7 +33,7 @@ public class Point implements Cloneable, PointImmutable { int x; int y; - public Point(int x, int y) { + public Point(final int x, final int y) { this.x=x; this.y=y; } @@ -42,35 +42,54 @@ public class Point implements Cloneable, PointImmutable { this(0, 0); } + @Override public Object cloneMutable() { return clone(); } - + + @Override public Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException ex) { + } catch (final CloneNotSupportedException ex) { throw new InternalError(); } } - public boolean equals(Object obj) { + @Override + public int compareTo(final PointImmutable d) { + final int sq = x*y; + final int xsq = d.getX()*d.getY(); + + if(sq > xsq) { + return 1; + } else if(sq < xsq) { + return -1; + } + return 0; + } + + @Override + public boolean equals(final Object obj) { if(this == obj) { return true; } if (obj instanceof Point) { - Point p = (Point)obj; + final Point p = (Point)obj; return y == p.y && x == p.x; } return false; } + @Override public final int getX() { return x; } + @Override public final int getY() { return y; } + @Override public int hashCode() { // 31 * x == (x << 5) - x int hash = 31 + x; @@ -78,29 +97,63 @@ public class Point implements Cloneable, PointImmutable { return hash; } + @Override public String toString() { - return new String( x + " / " + y ); + return x + " / " + y; } - public void setX(int x) { this.x = x; } - public void setY(int y) { this.y = y; } + public final void set(final int x, final int y) { this.x = x; this.y = y; } + public final void setX(final int x) { this.x = x; } + public final void setY(final int y) { this.y = y; } - public Point translate(Point pd) { + /** + * Translate this instance's x- and y-components, + * i.e. add the values of the given delta point to them. + * @param pd delta point + * @return this instance for scaling + */ + public final Point translate(final Point pd) { x += pd.x ; y += pd.y ; return this; } - public Point translate(int dx, int dy) { + /** + * Translate this instance's x- and y-components, + * i.e. add the given deltas to them. + * @param dx delta for x + * @param dy delta for y + * @return this instance for scaling + */ + public final Point translate(final int dx, final int dy) { x += dx ; y += dy ; return this; } - public Point scale(int sx, int sy) { + /** + * Scale this instance's x- and y-components, + * i.e. multiply them by the given scale factors. + * @param sx scale factor for x + * @param sy scale factor for y + * @return this instance for scaling + */ + public final Point scale(final int sx, final int sy) { x *= sx ; y *= sy ; return this; } - + + /** + * Inverse scale this instance's x- and y-components, + * i.e. divide them by the given scale factors. + * @param sx inverse scale factor for x + * @param sy inverse scale factor for y + * @return this instance for scaling + */ + public final Point scaleInv(final int sx, final int sy) { + x /= sx ; + y /= sy ; + return this; + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PointImmutable.java b/src/nativewindow/classes/javax/media/nativewindow/util/PointImmutable.java index d7eb0e7b4..08c628cc1 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/PointImmutable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PointImmutable.java @@ -32,21 +32,32 @@ package javax.media.nativewindow.util; import com.jogamp.common.type.WriteCloneable; /** Immutable Point interface */ -public interface PointImmutable extends WriteCloneable { +public interface PointImmutable extends WriteCloneable, Comparable<PointImmutable> { int getX(); int getY(); /** + * <p> + * Compares the square of the position. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final PointImmutable d); + + /** * Checks whether two points objects are equal. Two instances * of <code>PointReadOnly</code> are equal if the two components * <code>y</code> and <code>x</code> are equal. * @return <code>true</code> if the two points are equal; * otherwise <code>false</code>. */ + @Override public boolean equals(Object obj); + @Override public int hashCode(); - + } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/Rectangle.java b/src/nativewindow/classes/javax/media/nativewindow/util/Rectangle.java index 8d6bfe48f..c30968c4b 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/Rectangle.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/Rectangle.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,14 +20,16 @@ * 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 javax.media.nativewindow.util; +import java.util.List; + public class Rectangle implements Cloneable, RectangleImmutable { int x; int y; @@ -38,55 +40,198 @@ public class Rectangle implements Cloneable, RectangleImmutable { this(0, 0, 0, 0); } - public Rectangle(int x, int y, int width, int height) { + public Rectangle(final int x, final int y, final int width, final int height) { this.x=x; this.y=y; this.width=width; this.height=height; } - + + @Override public Object cloneMutable() { return clone(); } - + + @Override protected Object clone() { try { return super.clone(); - } catch (CloneNotSupportedException ex) { + } catch (final CloneNotSupportedException ex) { throw new InternalError(); } } + @Override public final int getX() { return x; } + @Override public final int getY() { return y; } + @Override public final int getWidth() { return width; } + @Override public final int getHeight() { return height; } - public void setX(int x) { this.x = x; } - public void setY(int y) { this.y = y; } - public void setWidth(int width) { this.width = width; } - public void setHeight(int height) { this.height = height; } - public boolean equals(Object obj) { + public final void set(final int x, final int y, final int width, final int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + public final void set(final Rectangle s) { + this.x = s.x; + this.y = s.y; + this.width = s.width; + this.height = s.height; + } + public final void setX(final int x) { this.x = x; } + public final void setY(final int y) { this.y = y; } + public final void setWidth(final int width) { this.width = width; } + public final void setHeight(final int height) { this.height = height; } + + @Override + public final RectangleImmutable union(final RectangleImmutable r) { + return union(r.getX(), r.getY(), r.getX() + r.getWidth(), r.getY() + r.getHeight()); + } + @Override + public final RectangleImmutable union(final int rx1, final int ry1, final int rx2, final int ry2) { + final int x1 = Math.min(x, rx1); + final int y1 = Math.min(y, ry1); + final int x2 = Math.max(x + width, rx2); + final int y2 = Math.max(y + height, ry2); + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } + /** + * Calculates the union of the given rectangles, stores it in this instance and returns this instance. + * @param rectangles given list of rectangles + * @return this instance holding the union of given rectangles. + */ + public final Rectangle union(final List<RectangleImmutable> rectangles) { + int x1=Integer.MAX_VALUE, y1=Integer.MAX_VALUE; + int x2=Integer.MIN_VALUE, y2=Integer.MIN_VALUE; + for(int i=rectangles.size()-1; i>=0; i--) { + final RectangleImmutable vp = rectangles.get(i); + x1 = Math.min(x1, vp.getX()); + x2 = Math.max(x2, vp.getX() + vp.getWidth()); + y1 = Math.min(y1, vp.getY()); + y2 = Math.max(y2, vp.getY() + vp.getHeight()); + } + set(x1, y1, x2 - x1, y2 - y1); + return this; + } + + @Override + public final RectangleImmutable intersection(final RectangleImmutable r) { + return intersection(r.getX(), r.getY(), r.getX() + r.getWidth(), r.getY() + r.getHeight()); + } + @Override + public final RectangleImmutable intersection(final int rx1, final int ry1, final int rx2, final int ry2) { + final int x1 = Math.max(x, rx1); + final int y1 = Math.max(y, ry1); + final int x2 = Math.min(x + width, rx2); + final int y2 = Math.min(y + height, ry2); + final int ix, iy, iwidth, iheight; + if( x2 < x1 ) { + ix = 0; + iwidth = 0; + } else { + ix = x1; + iwidth = x2 - x1; + } + if( y2 < y1 ) { + iy = 0; + iheight = 0; + } else { + iy = y1; + iheight = y2 - y1; + } + return new Rectangle (ix, iy, iwidth, iheight); + } + @Override + public final float coverage(final RectangleImmutable r) { + final RectangleImmutable isect = intersection(r); + final float sqI = isect.getWidth()*isect.getHeight(); + final float sqT = width*height; + return sqI / sqT; + } + + /** + * Scale this instance's components, + * i.e. multiply them by the given scale factors. + * @param sx scale factor for x + * @param sy scale factor for y + * @return this instance for scaling + */ + public final Rectangle scale(final int sx, final int sy) { + x *= sx ; + y *= sy ; + width *= sx ; + height *= sy ; + return this; + } + + /** + * Inverse scale this instance's components, + * i.e. divide them by the given scale factors. + * @param sx inverse scale factor for x + * @param sy inverse scale factor for y + * @return this instance for scaling + */ + public final Rectangle scaleInv(final int sx, final int sy) { + x /= sx ; + y /= sy ; + width /= sx ; + height /= sy ; + return this; + } + + @Override + public int compareTo(final RectangleImmutable d) { + { + final int sq = width*height; + final int xsq = d.getWidth()*d.getHeight(); + + if(sq > xsq) { + return 1; + } else if(sq < xsq) { + return -1; + } + } + { + final int sq = x*y; + final int xsq = d.getX()*d.getY(); + + if(sq > xsq) { + return 1; + } else if(sq < xsq) { + return -1; + } + } + return 0; + } + + @Override + public boolean equals(final Object obj) { if(this == obj) { return true; } if (obj instanceof Rectangle) { - Rectangle rect = (Rectangle)obj; + final Rectangle rect = (Rectangle)obj; return (y == rect.y) && (x == rect.x) && (height == rect.height) && (width == rect.width); } return false; } + @Override public int hashCode() { - int sum1 = x + height; - int sum2 = width + y; - int val1 = sum1 * (sum1 + 1)/2 + x; - int val2 = sum2 * (sum2 + 1)/2 + y; - int sum3 = val1 + val2; + final int sum1 = x + height; + final int sum2 = width + y; + final int val1 = sum1 * (sum1 + 1)/2 + x; + final int val2 = sum2 * (sum2 + 1)/2 + y; + final int sum3 = val1 + val2; return sum3 * (sum3 + 1)/2 + val2; } + @Override public String toString() { - return new String("[ "+x+" / "+y+" "+width+" x "+height+" ]"); + return "[ "+x+" / "+y+" "+width+" x "+height+" ]"; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/RectangleImmutable.java b/src/nativewindow/classes/javax/media/nativewindow/util/RectangleImmutable.java index d3b43c864..7ca92ff53 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/RectangleImmutable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/RectangleImmutable.java @@ -31,7 +31,7 @@ package javax.media.nativewindow.util; import com.jogamp.common.type.WriteCloneable; /** Immutable Rectangle interface */ -public interface RectangleImmutable extends WriteCloneable { +public interface RectangleImmutable extends WriteCloneable, Comparable<RectangleImmutable> { int getHeight(); @@ -41,6 +41,35 @@ public interface RectangleImmutable extends WriteCloneable { int getY(); + /** Returns the union of this rectangle and the given rectangle. */ + RectangleImmutable union(final RectangleImmutable r); + /** Returns the union of this rectangleand the given coordinates. */ + RectangleImmutable union(final int rx1, final int ry1, final int rx2, final int ry2); + /** Returns the intersection of this rectangleand the given rectangle. */ + RectangleImmutable intersection(RectangleImmutable r); + /** Returns the intersection of this rectangleand the given coordinates. */ + RectangleImmutable intersection(final int rx1, final int ry1, final int rx2, final int ry2); + /** + * Returns the coverage of given rectangle w/ this this one, i.e. between <code>0.0</code> and <code>1.0</code>. + * <p> + * Coverage is computed by: + * <pre> + * isect = this.intersection(r); + * coverage = area( isect ) / area( this ) ; + * </pre> + * </p> + */ + float coverage(RectangleImmutable r); + + /** + * <p> + * Compares square of size 1st, if equal the square of position. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final RectangleImmutable d); + /** * Checks whether two rect objects are equal. Two instances * of <code>Rectangle</code> are equal if the four integer values @@ -49,8 +78,10 @@ public interface RectangleImmutable extends WriteCloneable { * @return <code>true</code> if the two rectangles are equal; * otherwise <code>false</code>. */ + @Override boolean equals(Object obj); + @Override int hashCode(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java b/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java index 8f21bc49b..601e6dd71 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java @@ -4,14 +4,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 @@ -21,25 +21,26 @@ * 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 javax.media.nativewindow.util; -/** Immutable SurfaceSize Class, consisting of it's read only components:<br> +/** + * Immutable SurfaceSize Class, consisting of it's read only components:<br> * <ul> - * <li>{@link javax.media.nativewindow.util.DimensionImmutable} size in pixels</li> + * <li>{@link javax.media.nativewindow.util.DimensionImmutable size in pixels}</li> * <li><code>bits per pixel</code></li> * </ul> */ -public class SurfaceSize { - DimensionImmutable resolution; - int bitsPerPixel; +public class SurfaceSize implements Comparable<SurfaceSize> { + final DimensionImmutable resolution; + final int bitsPerPixel; - public SurfaceSize(DimensionImmutable resolution, int bitsPerPixel) { + public SurfaceSize(final DimensionImmutable resolution, final int bitsPerPixel) { if(null==resolution || bitsPerPixel<=0) { throw new IllegalArgumentException("resolution must be set and bitsPerPixel greater 0"); } @@ -47,6 +48,7 @@ public class SurfaceSize { this.bitsPerPixel=bitsPerPixel; } + /** Returns the resolution in pixel units */ public final DimensionImmutable getResolution() { return resolution; } @@ -55,8 +57,30 @@ public class SurfaceSize { return bitsPerPixel; } + @Override public final String toString() { - return new String("[ "+resolution+" x "+bitsPerPixel+" bpp ]"); + return "[ "+resolution+" pixels x "+bitsPerPixel+" bpp ]"; + } + + /** + * <p> + * Compares {@link DimensionImmutable#compareTo(DimensionImmutable) resolution} 1st, if equal the bitsPerPixel. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final SurfaceSize ssz) { + final int rres = resolution.compareTo(ssz.getResolution()); + if( 0 != rres ) { + return rres; + } + final int xbpp = ssz.getBitsPerPixel(); + if(bitsPerPixel > xbpp) { + return 1; + } else if(bitsPerPixel < xbpp) { + return -1; + } + return 0; } /** @@ -67,16 +91,18 @@ public class SurfaceSize { * @return <code>true</code> if the two dimensions are equal; * otherwise <code>false</code>. */ - public final boolean equals(Object obj) { + @Override + public final boolean equals(final Object obj) { if(this == obj) { return true; } if (obj instanceof SurfaceSize) { - SurfaceSize p = (SurfaceSize)obj; + final SurfaceSize p = (SurfaceSize)obj; return getResolution().equals(p.getResolution()) && getBitsPerPixel() == p.getBitsPerPixel(); } return false; } + @Override public final int hashCode() { // 31 * x == (x << 5) - x int hash = 31 + getResolution().hashCode(); diff --git a/src/nativewindow/classes/jogamp/nativewindow/Debug.java b/src/nativewindow/classes/jogamp/nativewindow/Debug.java index e07fd1b57..f2a45377e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/Debug.java +++ b/src/nativewindow/classes/jogamp/nativewindow/Debug.java @@ -1,44 +1,36 @@ -/* - * Copyright (c) 2003-2005 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 - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * 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. +/** + * Copyright 2014 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 jogamp.nativewindow; +import java.security.AccessController; +import java.security.PrivilegedAction; + import com.jogamp.common.util.PropertyAccess; /** Helper routines for logging and debugging. */ @@ -47,41 +39,37 @@ public class Debug extends PropertyAccess { // Some common properties private static final boolean verbose; private static final boolean debugAll; - + static { - PropertyAccess.addTrustedPrefix("nativewindow.", Debug.class); + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + PropertyAccess.addTrustedPrefix("nativewindow."); + return null; + } } ); verbose = isPropertyDefined("nativewindow.verbose", true); debugAll = isPropertyDefined("nativewindow.debug", true); if (verbose) { - Package p = Package.getPackage("javax.media.nativewindow"); + final Package p = Package.getPackage("javax.media.nativewindow"); System.err.println("NativeWindow specification version " + p.getSpecificationVersion()); System.err.println("NativeWindow implementation version " + p.getImplementationVersion()); System.err.println("NativeWindow implementation vendor " + p.getImplementationVendor()); } } - public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias) { - return PropertyAccess.isPropertyDefined(property, jnlpAlias, null); - } - - public static String getProperty(final String property, final boolean jnlpAlias) { - return PropertyAccess.getProperty(property, jnlpAlias, null); - } - - public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias) { - return PropertyAccess.getBooleanProperty(property, jnlpAlias, null); - } - - public static boolean verbose() { + /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */ + public static final void initSingleton() {} + + public static final boolean verbose() { return verbose; } - public static boolean debugAll() { + public static final boolean debugAll() { return debugAll; } - public static boolean debug(String subcomponent) { + public static final boolean debug(final String subcomponent) { return debugAll() || isPropertyDefined("nativewindow.debug." + subcomponent, true); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java index 52e9c8308..6061c4e79 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2009 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 @@ -36,8 +36,9 @@ package jogamp.nativewindow; import javax.media.nativewindow.*; public class DefaultGraphicsConfigurationFactoryImpl extends GraphicsConfigurationFactory { + @Override protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) { + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, final CapabilitiesChooser chooser, final AbstractGraphicsScreen screen, final int nativeVisualID) { return new DefaultGraphicsConfiguration(screen, capsChosen, capsRequested); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java index 743d371b7..4f6c0d155 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 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: @@ -25,52 +25,58 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package jogamp.nativewindow.jawt.x11; -import jogamp.nativewindow.jawt.*; -import jogamp.nativewindow.x11.X11Lib; -import jogamp.nativewindow.x11.X11Util; +package jogamp.nativewindow; + import javax.media.nativewindow.ToolkitLock; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; /** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. - * <br> - * This strategy should only be used if AWT is using the underlying native windowing toolkit - * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call - * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets. + * Implementing a global recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * This is the last resort for unstable driver where multiple X11 display connections + * to the same connection name are not treated thread safe within the GL/X11 driver. + * </p> */ -public class X11JAWTToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; +public class GlobalToolkitLock implements ToolkitLock { + private static final RecursiveLock globalLock = LockFactory.createRecursiveLock(); + private static GlobalToolkitLock singleton = new GlobalToolkitLock(); - public X11JAWTToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } + public static final GlobalToolkitLock getSingleton() { + return singleton; } + private GlobalToolkitLock() { } + + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } - JAWTUtil.lockToolkit(); - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); - } + globalLock.lock(); + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" GlobalToolkitLock: lock() "+toStringImpl()); } } + @Override public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } - JAWTUtil.unlockToolkit(); + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" GlobalToolkitLock: unlock() "+toStringImpl()); } + globalLock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + globalLock.validateLocked(); + } + + @Override + public final void dispose() { + // nop + } + + @Override + public String toString() { + return "GlobalToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "obj 0x"+Integer.toHexString(hashCode())+", isOwner "+globalLock.isOwner(Thread.currentThread())+", "+globalLock.toString(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java index 6c15f9a2b..8d0d04161 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.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,12 +20,12 @@ * 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 jogamp.nativewindow; @@ -37,20 +37,17 @@ import com.jogamp.common.os.Platform; import com.jogamp.common.util.cache.TempJarCache; public class NWJNILibLoader extends JNILibLoaderBase { - - public static boolean loadNativeWindow(final String ossuffix) { - return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { - public Boolean run() { - Platform.initSingleton(); - final String libName = "nativewindow_"+ossuffix ; - if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { - // either: [jogl-all.jar, jogl-all-noawt.jar, jogl-all-mobile.jar] -> jogl-all-natives-<os.and.arch>.jar - // or: nativewindow-core.jar -> nativewindow-natives-<os.and.arch>.jar - addNativeJarLibs(new Class<?>[] { NWJNILibLoader.class }, "-all", new String[] { "-noawt", "-mobile", "-core" } ); - } - return new Boolean(loadLibrary(libName, false, NWJNILibLoader.class.getClassLoader())); - } - }).booleanValue(); - } - + public static boolean loadNativeWindow(final String ossuffix) { + return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { + @Override + public Boolean run() { + Platform.initSingleton(); + final String libName = "nativewindow_"+ossuffix ; + if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { + JNILibLoaderBase.addNativeJarLibsJoglCfg(new Class<?>[] { jogamp.nativewindow.Debug.class }); + } + return Boolean.valueOf(loadLibrary(libName, false, NWJNILibLoader.class.getClassLoader())); + } + }).booleanValue(); + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index 29564da3b..40fca0f7b 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.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 @@ -46,12 +46,13 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); public static ToolkitLock getNullToolkitLock() { - return nullToolkitLock; + return nullToolkitLock; } - + // This subclass of NativeWindowFactory handles the case of // NativeWindows being passed in - protected NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException { + @Override + protected NativeWindow getNativeWindowImpl(final Object winObj, final AbstractGraphicsConfiguration config) throws IllegalArgumentException { if (winObj instanceof NativeWindow) { // Use the NativeWindow directly return (NativeWindow) winObj; @@ -69,10 +70,10 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { winObj.getClass().getName() + " is unsupported; expected " + "javax.media.nativewindow.NativeWindow or "+AWTNames.ComponentClass); } - + private Constructor<?> nativeWindowConstructor = null; - private NativeWindow getAWTNativeWindow(Object winObj, AbstractGraphicsConfiguration config) { + private NativeWindow getAWTNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config) { if (nativeWindowConstructor == null) { try { final String windowingType = getNativeWindowType(true); @@ -93,16 +94,16 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { } nativeWindowConstructor = ReflectionUtil.getConstructor( - windowClassName, new Class[] { Object.class, AbstractGraphicsConfiguration.class }, - getClass().getClassLoader()); - } catch (Exception e) { + windowClassName, new Class[] { Object.class, AbstractGraphicsConfiguration.class }, + true, getClass().getClassLoader()); + } catch (final Exception e) { throw new IllegalArgumentException(e); } } try { return (NativeWindow) nativeWindowConstructor.newInstance(new Object[] { winObj, config }); - } catch (Exception ie) { + } catch (final Exception ie) { throw new IllegalArgumentException(ie); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java index 1af6bf279..bbfb585ac 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java @@ -28,26 +28,48 @@ package jogamp.nativewindow; +import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ToolkitLock; /** - * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock} - * without any locking. Since there is no locking it all, - * it is intrinsically recursive. + * Implementing a singleton global NOP {@link javax.media.nativewindow.ToolkitLock} + * without any locking. Since there is no locking it all, it is intrinsically recursive. */ public class NullToolkitLock implements ToolkitLock { - /** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */ protected NullToolkitLock() { } - + + @Override public final void lock() { if(TRACE_LOCK) { - System.err.println("NullToolkitLock.lock()"); - // Thread.dumpStack(); + System.err.println(Thread.currentThread()+" NullToolkitLock: lock() "+toStringImpl()); + // ExceptionUtils.dumpStackTrace(System.err, 1, 4); } } + @Override public final void unlock() { - if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" NullToolkitLock: unlock() "+toStringImpl()); } + } + + @Override + public final void validateLocked() throws RuntimeException { + if( NativeWindowFactory.requiresToolkitLock() ) { + throw new RuntimeException("NullToolkitLock does not lock, but locking is required."); + } } + + @Override + public final void dispose() { + // nop + } + + @Override + public String toString() { + return "NullToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "obj 0x"+Integer.toHexString(hashCode()); + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java index 63f56cbae..deb685b51 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java @@ -36,17 +36,15 @@ import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.UpstreamSurfaceHook; - import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; -public abstract class ProxySurfaceImpl implements ProxySurface { +public abstract class ProxySurfaceImpl implements ProxySurface { private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - protected long displayHandle; // convenient ref of config.screen.device.handle private AbstractGraphicsConfiguration config; // control access due to delegation private UpstreamSurfaceHook upstream; private long surfaceHandle_old; - private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); private int implBitfield; private boolean upstreamSurfaceHookLifecycleEnabled; @@ -57,7 +55,7 @@ public abstract class ProxySurfaceImpl implements ProxySurface { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. */ - protected ProxySurfaceImpl(AbstractGraphicsConfiguration cfg, UpstreamSurfaceHook upstream, boolean ownsDevice) { + protected ProxySurfaceImpl(final AbstractGraphicsConfiguration cfg, final UpstreamSurfaceHook upstream, final boolean ownsDevice) { if(null == cfg) { throw new IllegalArgumentException("null AbstractGraphicsConfiguration"); } @@ -65,38 +63,41 @@ public abstract class ProxySurfaceImpl implements ProxySurface { throw new IllegalArgumentException("null UpstreamSurfaceHook"); } this.config = cfg; - this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); this.upstream = upstream; this.surfaceHandle_old = 0; this.implBitfield = 0; this.upstreamSurfaceHookLifecycleEnabled = true; if(ownsDevice) { addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); - } + } + } + + @Override + public final NativeSurface getUpstreamSurface() { + return upstream.getUpstreamSurface(); } @Override public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; } - + @Override - public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook) { + public void setUpstreamSurfaceHook(final UpstreamSurfaceHook hook) { if(null == hook) { throw new IllegalArgumentException("null UpstreamSurfaceHook"); } upstream = hook; } - + @Override - public final void enableUpstreamSurfaceHookLifecycle(boolean enable) { + public final void enableUpstreamSurfaceHookLifecycle(final boolean enable) { upstreamSurfaceHookLifecycleEnabled = enable; } - + @Override - public void createNotify() { + public void createNotify() { if(upstreamSurfaceHookLifecycleEnabled) { upstream.create(this); } - this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); this.surfaceHandle_old = 0; } @@ -111,25 +112,15 @@ public abstract class ProxySurfaceImpl implements ProxySurface { } invalidateImpl(); } - this.displayHandle = 0; this.surfaceHandle_old = 0; } - - /** + + /** * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed. - * @see #destroyNotify() + * @see #destroyNotify() */ protected void invalidateImpl() { - throw new InternalError("UpstreamSurfaceHook given, but required method not implemented."); - } - - @Override - public final long getDisplayHandle() { - return displayHandle; - } - - protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { - return config; + throw new InternalError("UpstreamSurfaceHook given, but required method not implemented."); } @Override @@ -138,10 +129,15 @@ public abstract class ProxySurfaceImpl implements ProxySurface { } @Override - public final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) { + public final long getDisplayHandle() { + return config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); + } + + @Override + public final void setGraphicsConfiguration(final AbstractGraphicsConfiguration cfg) { config = cfg; } - + @Override public final int getScreenIndex() { return getGraphicsConfiguration().getScreen().getIndex(); @@ -152,15 +148,15 @@ public abstract class ProxySurfaceImpl implements ProxySurface { @Override public abstract void setSurfaceHandle(long surfaceHandle); - + @Override - public final int getWidth() { - return upstream.getWidth(this); + public final int getSurfaceWidth() { + return upstream.getSurfaceWidth(this); } @Override - public final int getHeight() { - return upstream.getHeight(this); + public final int getSurfaceHeight() { + return upstream.getSurfaceHeight(this); } @Override @@ -169,22 +165,22 @@ public abstract class ProxySurfaceImpl implements ProxySurface { } @Override - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + public void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } @Override - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); } @Override - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + public void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); } @Override - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); } @@ -253,7 +249,8 @@ public abstract class ProxySurfaceImpl implements ProxySurface { public final Thread getSurfaceLockOwner() { return surfaceLock.getOwner(); } - + + @Override public final StringBuilder getUpstreamOptionBits(StringBuilder sink) { if(null == sink) { sink = new StringBuilder(); @@ -285,38 +282,41 @@ public abstract class ProxySurfaceImpl implements ProxySurface { sink.append(" ]"); return sink; } - + @Override public final int getUpstreamOptionBits() { return implBitfield; } - + @Override - public final boolean containsUpstreamOptionBits(int v) { + public final boolean containsUpstreamOptionBits(final int v) { return v == ( implBitfield & v ) ; } - + @Override - public final void addUpstreamOptionBits(int v) { implBitfield |= v; } - + public final void addUpstreamOptionBits(final int v) { implBitfield |= v; } + @Override - public final void clearUpstreamOptionBits(int v) { implBitfield &= ~v; } - + public final void clearUpstreamOptionBits(final int v) { implBitfield &= ~v; } + @Override public StringBuilder toString(StringBuilder sink) { if(null == sink) { sink = new StringBuilder(); } - sink.append(getUpstreamSurfaceHook()). - append(", displayHandle 0x" + Long.toHexString(getDisplayHandle())). - append(", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())). - append(", size " + getWidth() + "x" + getHeight()).append(", "); + sink.append("displayHandle 0x" + Long.toHexString(getDisplayHandle())). + append("\n, surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())). + append("\n, size " + getSurfaceWidth() + "x" + getSurfaceHeight()).append("\n, "); getUpstreamOptionBits(sink); - sink.append(", surfaceLock "+surfaceLock); + sink.append("\n, "+config). + append("\n, surfaceLock "+surfaceLock+"\n, "). + append(getUpstreamSurfaceHook()). + append("\n, upstreamSurface "+(null != getUpstreamSurface())); + // append("\n, upstreamSurface "+getUpstreamSurface()); return sink; } - + @Override public String toString() { - StringBuilder msg = new StringBuilder(); + final StringBuilder msg = new StringBuilder(); msg.append(getClass().getSimpleName()).append("[ "); toString(msg); msg.append(" ]"); diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java index 5166ef577..e4e557d36 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 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: @@ -25,7 +25,8 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package jogamp.nativewindow.x11; + +package jogamp.nativewindow; import javax.media.nativewindow.ToolkitLock; @@ -33,38 +34,53 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; /** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing {@link X11Util#XLockDisplay(long)}. - * <br> - * This strategy should not be used in case XInitThreads() is being used, - * or a higher level toolkit lock is required, ie AWT lock. + * Implementing a resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * A resource handle maybe used within a unique object + * and can be synchronized across threads via an instance of ResourceToolkitLock. + * </p> */ -public class X11ToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; +public class ResourceToolkitLock implements ToolkitLock { + public static final ResourceToolkitLock create() { + return new ResourceToolkitLock(); + } - public X11ToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } + private final RecursiveLock lock; + + private ResourceToolkitLock() { + this.lock = LockFactory.createRecursiveLock(); } + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); + lock.lock(); + if(TRACE_LOCK) { + System.err.println(Thread.currentThread()+" ResourceToolkitLock: lock() "+toStringImpl()); + // ExceptionUtils.dumpStackTrace(System.err, 1, 4); } } + @Override public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" ResourceToolkitLock: unlock() "+toStringImpl()); } + lock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); + } + + @Override + public final void dispose() { + // nop + } + + @Override + public String toString() { + return "ResourceToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java new file mode 100644 index 000000000..881fd56a6 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -0,0 +1,152 @@ +/** + * Copyright 2012 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 jogamp.nativewindow; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a shared resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * A resource handle maybe used within many objects + * and can be synchronized across threads via an unique instance of SharedResourceToolkitLock. + * </p> + * <p> + * Implementation holds a synchronized map from handle to reference counted {@link SharedResourceToolkitLock}. + * New elements are added via {@link #get(long)} if new + * and removed via {@link #dispose()} if no more referenced. + * </p> + */ +public class SharedResourceToolkitLock implements ToolkitLock { + private static final LongObjectHashMap handle2Lock; + static { + handle2Lock = new LongObjectHashMap(); + handle2Lock.setKeyNotFoundValue(null); + } + + /** + * @return number of unclosed EGL Displays.<br> + */ + public static int shutdown(final boolean verbose) { + if(DEBUG || verbose || handle2Lock.size() > 0 ) { + System.err.println("SharedResourceToolkitLock: Shutdown (open: "+handle2Lock.size()+")"); + if(DEBUG) { + Thread.dumpStack(); + } + if( handle2Lock.size() > 0) { + dumpOpenDisplayConnections(); + } + } + return handle2Lock.size(); + } + + public static void dumpOpenDisplayConnections() { + System.err.println("SharedResourceToolkitLock: Open ResourceToolkitLock's: "+handle2Lock.size()); + int i=0; + for(final Iterator<LongObjectHashMap.Entry> iter = handle2Lock.iterator(); iter.hasNext(); i++) { + final LongObjectHashMap.Entry e = iter.next(); + System.err.println("SharedResourceToolkitLock: Open["+i+"]: "+e.value); + } + } + + public static final SharedResourceToolkitLock get(final long handle) { + SharedResourceToolkitLock res; + synchronized(handle2Lock) { + res = (SharedResourceToolkitLock) handle2Lock.get(handle); + if( null == res ) { + res = new SharedResourceToolkitLock(handle); + res.refCount.incrementAndGet(); + handle2Lock.put(handle, res); + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * NEW *: "+res); } + } else { + res.refCount.incrementAndGet(); + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * EXIST *: "+res); } + } + } + return res; + } + + private final RecursiveLock lock; + private final long handle; + private final AtomicInteger refCount; + + private SharedResourceToolkitLock(final long handle) { + this.lock = LockFactory.createRecursiveLock(); + this.handle = handle; + this.refCount = new AtomicInteger(0); + } + + + @Override + public final void lock() { + lock.lock(); + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" SharedResourceToolkitLock: lock() "+toStringImpl()); } + } + + @Override + public final void unlock() { + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" SharedResourceToolkitLock: unlock() "+toStringImpl()); } + lock.unlock(); + } + + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); + } + + @Override + public final void dispose() { + if(0 < refCount.get()) { // volatile OK + synchronized(handle2Lock) { + if( 0 == refCount.decrementAndGet() ) { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * REMOV *: "+this); } + handle2Lock.remove(handle); + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * DOWN *: "+this); } + } + } + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * NULL *: "+this); } + } + } + + @Override + public String toString() { + return "SharedResourceToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "refCount "+refCount+", handle 0x"+Long.toHexString(handle)+", obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString(); + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java new file mode 100644 index 000000000..73413cf59 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java @@ -0,0 +1,172 @@ +/** + * Copyright 2014 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 jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ScalableSurface; + +/** + * Basic {@link ScalableSurface} utility to validate and compute pixel-scale values. + */ +public class SurfaceScaleUtils { + + private static final int[] PlatformMaxPixelScale; + private static final boolean PlatformUniformPixelScale; + private static final boolean PlatformPixelScaleSupported; + + static { + if( NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(true) ) { + PlatformMaxPixelScale = new int[] { jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE, jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE }; + PlatformUniformPixelScale = true; + PlatformPixelScaleSupported = true; + } else { + PlatformMaxPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + PlatformUniformPixelScale = false; + PlatformPixelScaleSupported = false; + } + } + + /** + * Compute a new valid pixelScale to be used by {@link NativeSurface} implementations, + * based on the given request and surface's pixelScale + * + * @param result int[2] storage for result, maybe same as <code>prePixelScale</code> for in-place + * @param prePixelScale previous pixelScale + * @param reqPixelScale requested pixelScale, validated via {@link #validateReqPixelScale(int[], int, String)}. + * @param newPixelScaleRaw new raw surface pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + * @return true if pixelScale has changed, otherwise false + */ + public static boolean computePixelScale(final int[] result, final int[] prePixelScale, final int[] reqPixelScale, final int[] newPixelScaleRaw, final String DEBUG_PREFIX) { + final int newPixelScaleSafeX = 0 < newPixelScaleRaw[0] ? newPixelScaleRaw[0] : ScalableSurface.IDENTITY_PIXELSCALE; + final int newPixelScaleSafeY = 0 < newPixelScaleRaw[1] ? newPixelScaleRaw[1] : ScalableSurface.IDENTITY_PIXELSCALE; + final boolean useHiDPI = ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[0] || ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[1]; + final int prePixelScaleX = prePixelScale[0]; + final int prePixelScaleY = prePixelScale[1]; + + if( useHiDPI ) { + result[0] = newPixelScaleSafeX; + result[1] = newPixelScaleSafeY; + } else { + result[0] = ScalableSurface.IDENTITY_PIXELSCALE; + result[1] = ScalableSurface.IDENTITY_PIXELSCALE; + } + + final boolean changed = result[0] != prePixelScaleX || result[1] != prePixelScaleY; + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".computePixelScale: useHiDPI "+useHiDPI+", ["+prePixelScaleX+"x"+prePixelScaleY+" (pre), "+ + reqPixelScale[0]+"x"+reqPixelScale[1]+" (req)] -> "+ + newPixelScaleRaw[0]+"x"+newPixelScaleRaw[1]+" (raw) -> "+ + newPixelScaleSafeX+"x"+newPixelScaleSafeY+" (safe) -> "+ + result[0]+"x"+result[1]+" (use), changed "+changed); + } + return changed; + } + + /** + * Validate the given requested pixelScale value pair, i.e. clip it to the + * limits of {@link ScalableSurface#AUTOMAX_PIXELSCALE} and {@link #getPlatformMaxPixelScale(int[])} + * <p> + * To be used by {@link ScalableSurface#setSurfaceScale(int[])} implementations. + * </p> + * + * @param result int[2] storage for result + * @param reqPixelScale requested pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + */ + public static void validateReqPixelScale(final int[] result, final int[] reqPixelScale, final String DEBUG_PREFIX) { + final int minPS = Math.min(reqPixelScale[0], reqPixelScale[1]); + if( ScalableSurface.AUTOMAX_PIXELSCALE >= minPS ) { + result[0] = ScalableSurface.AUTOMAX_PIXELSCALE; + result[1] = ScalableSurface.AUTOMAX_PIXELSCALE; + } else if( PlatformUniformPixelScale ) { + final int maxPS = Math.max(reqPixelScale[0], reqPixelScale[1]); + if( maxPS >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + result[1] = PlatformMaxPixelScale[1]; + } else { + result[0] = maxPS; + result[1] = maxPS; + } + } else { + if( reqPixelScale[0] >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + } else { + result[0] = reqPixelScale[0]; + } + if( reqPixelScale[1] >= PlatformMaxPixelScale[1] ) { + result[1] = PlatformMaxPixelScale[1]; + } else { + result[1] = reqPixelScale[1]; + } + } + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".validateReqPixelScale: ["+reqPixelScale[0]+"x"+reqPixelScale[1]+" (req), "+ + PlatformMaxPixelScale[0]+"x"+PlatformMaxPixelScale[1]+" (max)] -> "+ + result[0]+"x"+result[1]+" (valid)"); + } + } + + /** + * Replaces {@link ScalableSurface#AUTOMAX_PIXELSCALE} with {@link #getPlatformMaxPixelScale(int[])}, + * for each component. + * + * @param pixelScale int[2] value array to be tested and replaced + */ + public static void replaceAutoMaxWithPlatformMax(final int[] pixelScale) { + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[0] ) { + pixelScale[0] = PlatformMaxPixelScale[0]; + } + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[1] ) { + pixelScale[1] = PlatformMaxPixelScale[1]; + } + } + + /** + * Returns the maximum platform pixelScale + */ + public static int[] getPlatformMaxPixelScale(final int[] result) { + System.arraycopy(PlatformMaxPixelScale, 0, result, 0, 2); + return result; + } + + /** + * Returns true if platform pixelScale is uniform, i.e. same scale factor for x- and y-direction, otherwise false. + */ + public static boolean isPlatformPixelScaleUniform() { + return PlatformUniformPixelScale; + } + + /** + * Returns whether the platform supports pixelScale + */ + public static boolean isPlatformPixelScaleSupported() { + return PlatformPixelScaleSupported; + } + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java index 4f68c6945..a7e136f76 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.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,7 +20,7 @@ * 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. @@ -36,48 +36,56 @@ import javax.media.nativewindow.SurfaceUpdatedListener; public class SurfaceUpdatedHelper implements SurfaceUpdatedListener { private final Object surfaceUpdatedListenersLock = new Object(); private final ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); + private volatile boolean isEmpty = true; // // Management Utils - // - public int size() { return surfaceUpdatedListeners.size(); } - public SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); } - + // + public final int size() { return surfaceUpdatedListeners.size(); } + public final SurfaceUpdatedListener get(final int i) { return surfaceUpdatedListeners.get(i); } + // // Implementation of NativeSurface SurfaceUpdatedListener methods - // - - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + // + + public final void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { addSurfaceUpdatedListener(-1, l); } - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + public final void addSurfaceUpdatedListener(int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { if(l == null) { return; } synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size(); + if(0>index) { + index = surfaceUpdatedListeners.size(); } surfaceUpdatedListeners.add(index, l); + isEmpty = false; } } - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + public final boolean removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { if (l == null) { - return; + return false; } synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners.remove(l); + final boolean res = surfaceUpdatedListeners.remove(l); + isEmpty = 0 == surfaceUpdatedListeners.size(); + return res; } } - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + @Override + public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { + if( isEmpty ) { + return; + } synchronized(surfaceUpdatedListenersLock) { for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { - SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); + final SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); l.surfaceUpdated(updater, ns, when); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java new file mode 100644 index 000000000..47b3e63fa --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java @@ -0,0 +1,47 @@ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; + +/** + * Marker interface. + * <p> + * Implementation requires to provide static methods: + * <pre> + public static void initSingleton() {} + + public static void shutdown() {} + + public static boolean requiresToolkitLock() {} + + public static boolean hasThreadingIssues() {} + * </pre> + * Above static methods are invoked by {@link NativeWindowFactory#initSingleton()}, + * or {@link NativeWindowFactory#shutdown()} via reflection. + * </p> + */ +public interface ToolkitProperties { + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // void initSingleton(); + + /** + * Cleanup resources. + * <p> + * Called by {@link NativeWindowFactory#shutdown()} + * </p> + */ + // void shutdown(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean requiresToolkitLock(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean hasThreadingIssues(); + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index e544bc61a..d3439b53f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -31,17 +31,24 @@ package jogamp.nativewindow; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.ScalableSurface; import javax.media.nativewindow.UpstreamSurfaceHook; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; -public class WrappedSurface extends ProxySurfaceImpl { - protected long surfaceHandle; +/** + * Generic Surface implementation which wraps an existing window handle. + * + * @see ProxySurface + */ +public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface { + private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private long surfaceHandle; /** * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information, * which is being passed to the {@link ProxySurface} instance. - * + * * @param cfg the {@link AbstractGraphicsConfiguration} to be used * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined * @param initialWidth @@ -50,11 +57,11 @@ public class WrappedSurface extends ProxySurfaceImpl { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. */ - public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, boolean ownsDevice) { + public WrappedSurface(final AbstractGraphicsConfiguration cfg, final long handle, final int initialWidth, final int initialHeight, final boolean ownsDevice) { super(cfg, new UpstreamSurfaceHookMutableSize(initialWidth, initialHeight), ownsDevice); surfaceHandle=handle; } - + /** * @param cfg the {@link AbstractGraphicsConfiguration} to be used * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined @@ -63,14 +70,16 @@ public class WrappedSurface extends ProxySurfaceImpl { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. */ - public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, UpstreamSurfaceHook upstream, boolean ownsDevice) { + public WrappedSurface(final AbstractGraphicsConfiguration cfg, final long handle, final UpstreamSurfaceHook upstream, final boolean ownsDevice) { super(cfg, upstream, ownsDevice); surfaceHandle=handle; } @Override - protected void invalidateImpl() { + protected void invalidateImpl() { surfaceHandle = 0; + hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; } @Override @@ -79,10 +88,10 @@ public class WrappedSurface extends ProxySurfaceImpl { } @Override - public final void setSurfaceHandle(long surfaceHandle) { + public final void setSurfaceHandle(final long surfaceHandle) { this.surfaceHandle=surfaceHandle; } - + @Override protected final int lockSurfaceImpl() { return LOCK_SUCCESS; @@ -92,4 +101,73 @@ public class WrappedSurface extends ProxySurfaceImpl { protected final void unlockSurfaceImpl() { } -} + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + pixelUnitsAndResult[0] /= hasPixelScale[0]; + pixelUnitsAndResult[1] /= hasPixelScale[1]; + return pixelUnitsAndResult; + } + + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + windowUnitsAndResult[0] *= hasPixelScale[0]; + windowUnitsAndResult[1] *= hasPixelScale[1]; + return windowUnitsAndResult; + } + + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation is to simply pass the given pixelScale + * from the caller <i>down</i> to this instance without validation to be applied in the {@link #convertToPixelUnits(int[]) conversion} {@link #convertToWindowUnits(int[]) methods} <b>only</b>.<br/> + * This allows the caller to pass down knowledge about window- and pixel-unit conversion and utilize mentioned conversion methods. + * </p> + * <p> + * The given pixelScale will not impact the actual {@link #getSurfaceWidth()} and {@link #getSurfaceHeight()}, + * which is determinated by this instances {@link #getUpstreamSurface() upstream surface}. + * </p> + * <p> + * Implementation uses the default pixelScale {@link ScalableSurface#IDENTITY_PIXELSCALE} + * and resets to default values on {@link #invalidateImpl()}, i.e. {@link #destroyNotify()}. + * </p> + * <p> + * Implementation returns the given pixelScale array. + * </p> + */ + @Override + public final void setSurfaceScale(final int[] pixelScale) { + hasPixelScale[0] = pixelScale[0]; + hasPixelScale[1] = pixelScale[1]; + } + + @Override + public final int[] getRequestedSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 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(hasPixelScale, 0, result, 0, 2); + return result; + } + +}
\ No newline at end of file diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java new file mode 100644 index 000000000..fd39a3b4a --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java @@ -0,0 +1,120 @@ +package jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.nativewindow.util.Point; + +import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; + +public class WrappedWindow extends WrappedSurface implements NativeWindow { + private final InsetsImmutable insets = new Insets(0, 0, 0, 0); + private long windowHandle; + + /** + * Utilizes a {@link UpstreamWindowHookMutableSizePos} to hold the size and position information, + * which is being passed to the {@link ProxySurface} instance. + * + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param surfaceHandle the wrapped pre-existing native surface handle, maybe 0 if not yet determined + * @param initialWinX + * @param initialWinY + * @param initialWinWidth + * @param initialWinHeight + * @param initialPixelWidth FIXME: pixel-dim == window-dim 'for now' ? + * @param initialPixelHeight FIXME: pixel-dim == window-dim 'for now' ? + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. + */ + public WrappedWindow(final AbstractGraphicsConfiguration cfg, final long surfaceHandle, + final int initialWinX, final int initialWinY, final int initialWinWidth, final int initialWinHeight, + final int initialPixelWidth, final int initialPixelHeight, + final boolean ownsDevice, final long windowHandle) { + this(cfg, surfaceHandle, + new UpstreamWindowHookMutableSizePos(initialWinX, initialWinY, initialWinWidth, initialWinHeight, + initialPixelWidth, initialPixelHeight), + ownsDevice, windowHandle); + } + + /** + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param surfaceHandle the wrapped pre-existing native surface handle, maybe 0 if not yet determined + * @param upstream the {@link UpstreamSurfaceHook} to be used + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. + */ + public WrappedWindow(final AbstractGraphicsConfiguration cfg, final long surfaceHandle, final UpstreamWindowHookMutableSizePos upstream, final boolean ownsDevice, final long windowHandle) { + super(cfg, surfaceHandle, upstream, ownsDevice); + this.windowHandle = windowHandle; + } + + @Override + protected void invalidateImpl() { + super.invalidateImpl(); + windowHandle = 0; + } + + @Override + public void destroy() { + destroyNotify(); + } + + @Override + public final NativeSurface getNativeSurface() { return this; } + + @Override + public NativeWindow getParent() { + return null; + } + + @Override + public long getWindowHandle() { + return windowHandle; + } + + @Override + public InsetsImmutable getInsets() { + return insets; + } + + @Override + public int getX() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getX(); + } + + @Override + public int getY() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getY(); + } + + @Override + public int getWidth() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getWidth(); + } + + @Override + public int getHeight() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getHeight(); + } + + @Override + public Point getLocationOnScreen(final Point point) { + if(null!=point) { + return point; + } else { + return new Point(0, 0); + } + } + + @Override + public boolean hasFocus() { + return false; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java index d77cd75ef..b0eda63b6 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java +++ b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java @@ -27,17 +27,31 @@ */ package jogamp.nativewindow.awt; +import java.awt.Cursor; +import java.awt.FocusTraversalPolicy; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Toolkit; import java.awt.Window; import java.awt.Component; import java.awt.Container; import java.awt.Frame; +import java.awt.image.BufferedImage; +import java.util.HashMap; + +import javax.swing.JComponent; import javax.swing.JFrame; +import javax.swing.JRootPane; import javax.swing.WindowConstants; - import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormat; +import javax.media.nativewindow.util.PixelFormatUtil; import javax.swing.MenuSelectionManager; +import jogamp.nativewindow.jawt.JAWTUtil; + public class AWTMisc { public static JFrame getJFrame(Component c) { @@ -69,13 +83,157 @@ public class AWTMisc { } /** + * Return insets of the component w/o traversing up to parent, + * i.e. trying Window and JComponent. + * <p> + * Exception is JRootPane. + * Return it's parent's Window component's insets if available, + * otherwise return JRootPane's insets.<br> + * This is due to <i>experience</i> that <i>some</i> JRootPane's + * do not expose valid insets value. + * </p> + * @param topLevelOnly if true only returns insets of top-level components, i.e. Window and JRootPanel, + * otherwise for JComponent as well. + */ + public static Insets getInsets(final Component c, final boolean topLevelOnly) { + if( c instanceof Window ) { + return ((Window)c).getInsets(); + } + if( c instanceof JRootPane ) { + final Window w = getWindow(c); + if( null != w ) { + return w.getInsets(); + } + return ((JRootPane)c).getInsets(); + } + if( !topLevelOnly && c instanceof JComponent ) { + return ((JComponent)c).getInsets(); + } + return null; + } + + public static interface ComponentAction { + /** + * @param c the component to perform the action on + */ + public void run(Component c); + } + + public static int performAction(final Container c, final Class<?> cType, final ComponentAction action) { + int count = 0; + final int cc = c.getComponentCount(); + for(int i=0; i<cc; i++) { + final Component e = c.getComponent(i); + if( e instanceof Container ) { + count += performAction((Container)e, cType, action); + } else if( cType.isInstance(e) ) { + action.run(e); + count++; + } + } + // we come at last .. + if( cType.isInstance(c) ) { + action.run(c); + count++; + } + return count; + } + + /** + * Traverse to the next forward or backward component using the + * container's FocusTraversalPolicy. + * + * @param comp the assumed current focuse component + * @param forward if true, returns the next focus component, otherwise the previous one. + * @return + */ + public static Component getNextFocus(Component comp, final boolean forward) { + Container focusContainer = comp.getFocusCycleRootAncestor(); + while ( focusContainer != null && + ( !focusContainer.isShowing() || !focusContainer.isFocusable() || !focusContainer.isEnabled() ) ) + { + comp = focusContainer; + focusContainer = comp.getFocusCycleRootAncestor(); + } + Component next = null; + if (focusContainer != null) { + final FocusTraversalPolicy policy = focusContainer.getFocusTraversalPolicy(); + next = forward ? policy.getComponentAfter(focusContainer, comp) : policy.getComponentBefore(focusContainer, comp); + if (next == null) { + next = policy.getDefaultComponent(focusContainer); + } + } + return next; + } + + /** * Issue this when your non AWT toolkit gains focus to clear AWT menu path */ public static void clearAWTMenus() { MenuSelectionManager.defaultManager().clearSelectedPath(); } - public static WindowClosingProtocol.WindowClosingMode AWT2NWClosingOperation(int awtClosingOperation) { + static final HashMap<Integer, Cursor> cursorMap = new HashMap<Integer, Cursor>(); + static final Cursor nulCursor; + static { + Cursor _nulCursor = null; + if( !JAWTUtil.isHeadlessMode() ) { + try { + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + final BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR); + _nulCursor = toolkit.createCustomCursor(img, new Point(0,0), "nullCursor"); + } catch (final Exception he) { + if( JAWTUtil.DEBUG ) { + System.err.println("Caught exception: "+he.getMessage()); + he.printStackTrace(); + } + } + } + nulCursor = _nulCursor; + } + + public static synchronized Cursor getNullCursor() { return nulCursor; } + + public static synchronized Cursor getCursor(final PixelRectangle pixelrect, final Point hotSpot) { + // 31 * x == (x << 5) - x + int hash = 31 + pixelrect.hashCode(); + hash = ((hash << 5) - hash) + hotSpot.hashCode(); + final Integer key = Integer.valueOf(hash); + + Cursor cursor = cursorMap.get(key); + if( null == cursor ) { + cursor = createCursor(pixelrect, hotSpot); + cursorMap.put(key, cursor); + } + return cursor; + } + private static synchronized Cursor createCursor(final PixelRectangle pixelrect, final Point hotSpot) { + final int width = pixelrect.getSize().getWidth(); + final int height = pixelrect.getSize().getHeight(); + final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // PixelFormat.BGRA8888 + final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() { + public void store(final int x, final int y, final int pixel) { + img.setRGB(x, y, pixel); + } + @Override + public final PixelFormat getPixelformat() { + return PixelFormat.BGRA8888; + } + @Override + public int getStride() { + return width*4; + } + @Override + public final boolean isGLOriented() { + return false; + } + }; + PixelFormatUtil.convert32(imgSink, pixelrect); + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + return toolkit.createCustomCursor(img, hotSpot, pixelrect.toString()); + } + + public static WindowClosingProtocol.WindowClosingMode AWT2NWClosingOperation(final int awtClosingOperation) { switch (awtClosingOperation) { case WindowConstants.DISPOSE_ON_CLOSE: case WindowConstants.EXIT_ON_CLOSE: @@ -88,7 +246,7 @@ public class AWTMisc { } } - public static WindowClosingProtocol.WindowClosingMode getNWClosingOperation(Component c) { + public static WindowClosingProtocol.WindowClosingMode getNWClosingOperation(final Component c) { final JFrame jf = getJFrame(c); final int op = (null != jf) ? jf.getDefaultCloseOperation() : WindowConstants.DO_NOTHING_ON_CLOSE ; return AWT2NWClosingOperation(op); diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java index f579da217..8aaffbd84 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2003 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 @@ -28,11 +28,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. */ @@ -47,15 +47,16 @@ import java.awt.Toolkit; import java.security.AccessController; import java.security.PrivilegedAction; -public class JAWTJNILibLoader extends NWJNILibLoader { +public class JAWTJNILibLoader extends NWJNILibLoader { static { AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { // Make sure that awt.dll is loaded before loading jawt.dll. Otherwise // a Dialog with "awt.dll not found" might pop up. // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4481947. Toolkit.getDefaultToolkit(); - + // Must pre-load JAWT on all non-Mac platforms to // ensure references from jogl_awt shared object // will succeed since JAWT shared object isn't in @@ -63,7 +64,7 @@ public class JAWTJNILibLoader extends NWJNILibLoader { if ( NativeWindowFactory.TYPE_MACOSX != NativeWindowFactory.getNativeWindowType(false) ) { try { loadLibrary("jawt", null, true, JAWTJNILibLoader.class.getClassLoader()); - } catch (Throwable t) { + } catch (final Throwable t) { // It might be ok .. if it's already loaded if(DEBUG) { t.printStackTrace(); @@ -74,9 +75,9 @@ public class JAWTJNILibLoader extends NWJNILibLoader { } }); } - + public static void initSingleton() { - // just exist to ensure static init has been run + // just exist to ensure static init has been run } - + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index f1e8a786a..231a89c26 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,7 +29,7 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. @@ -38,6 +38,8 @@ package jogamp.nativewindow.jawt; import java.awt.EventQueue; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.lang.reflect.InvocationTargetException; @@ -51,23 +53,30 @@ import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ToolkitLock; +import jogamp.common.os.PlatformPropsImpl; import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NWJNILibLoader; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.VersionNumber; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; public class JAWTUtil { public static final boolean DEBUG = Debug.debug("JAWT"); + private static final boolean SKIP_AWT_HIDPI; + /** OSX JAWT version option to use CALayer */ public static final int JAWT_MACOSX_USE_CALAYER = 0x80000000; - + /** OSX JAWT CALayer availability on Mac OS X >= 10.6 Update 4 (recommended) */ public static final VersionNumber JAWT_MacOSXCALayerMinVersion = new VersionNumber(10,6,4); - + /** OSX JAWT CALayer required with Java >= 1.7.0 (implies OS X >= 10.7 */ - public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = new VersionNumber(1,7,0); - + public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = Platform.Version17; + // See whether we're running in headless mode private static final boolean headlessMode; private static final JAWT jawtLockObject; @@ -80,75 +89,196 @@ public class JAWTUtil { private static final Method sunToolkitAWTUnlockMethod; private static final boolean hasSunToolkitAWTLock; + private static final RecursiveLock jawtLock; private static final ToolkitLock jawtToolkitLock; + private static final Method getScaleFactorMethod; + private static class PrivilegedDataBlob1 { PrivilegedDataBlob1() { ok = false; - } - Method sunToolkitAWTLockMethod; - Method sunToolkitAWTUnlockMethod; + } + Method sunToolkitAWTLockMethod; + Method sunToolkitAWTUnlockMethod; + Method getScaleFactorMethod; boolean ok; } - + /** * Returns true if this platform's JAWT implementation supports offscreen layer. */ public static boolean isOffscreenLayerSupported() { - return Platform.OS_TYPE == Platform.OSType.MACOS && - Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0; + return PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && + PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0; } - + /** * Returns true if this platform's JAWT implementation requires using offscreen layer. */ public static boolean isOffscreenLayerRequired() { - return Platform.OS_TYPE == Platform.OSType.MACOS && - Platform.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0; + return PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && + PlatformPropsImpl.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0; } - + + /** + * CALayer size needs to be set using the AWT component size. + * <p> + * AWT's super-calayer, i.e. the AWT's own component CALayer, + * does not layout our root-calayer in respect to this component's + * position and size, at least when resizing programmatically. + * </p> + * <p> + * As of today, this flag is enabled for all known AWT versions. + * </p> + * <p> + * Sync w/ NativeWindowProtocols.h + * </p> + */ + public static final int JAWT_OSX_CALAYER_QUIRK_SIZE = 1 << 0; + + /** + * CALayer position needs to be set to zero. + * <p> + * AWT's super-calayer, i.e. the AWT's own component CALayer, + * has a broken layout and needs it's sub-layers to be located at position 0/0. + * </p> + * <p> + * See <code>http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172187</code>. + * </p> + * <p> + * Further more a re-layout seems to be required in this case, + * i.e. a programmatic forced resize +1 and it's inverted resize -1. + * </p> + * <p> + * This flag is enabled w/ AWT < 1.7.0_40. + * </p> + * <p> + * Sync w/ NativeWindowProtocols.h + * </p> + */ + public static final int JAWT_OSX_CALAYER_QUIRK_POSITION = 1 << 1; + + /** + * CALayer position needs to be derived from AWT position + * in relation to super CALayer. + * <p> + * AWT's super-calayer, i.e. the AWT top-container's CALayer, + * does not layout our root-calayer in respect to this component's + * position and size, at least when resizing programmatically. + * </p> + * <p> + * CALayer position has origin 0/0 at bottom/left, + * where AWT component has origin 0/0 at top/left. + * </p> + * <p> + * The super-calayer bounds exclude the frame's heavyweight border/insets. + * </p> + * <p> + * The super-calayer lies within the AWT top-container client space (content). + * </p> + * <p> + * Component's location in super-calayer: + * <pre> + p0 = c.locationOnScreen(); + p0 -= c.getOutterComp.getPos(); + p0 -= c.getOutterComp.getInsets(); + * </pre> + * Where 'locationOnScreen()' is: + * <pre> + p0 = 0/0; + while( null != c ) { + p0 += c.getPos(); + } + * </pre> + * </p> + * <p> + * This flags also sets {@link #JAWT_OSX_CALAYER_QUIRK_SIZE}, + * i.e. they are related. + * </p> + * <p> + * As of today, this flag is enabled for w/ AWT >= 1.7.0_40. + * </p> + * <p> + * Sync w/ NativeWindowProtocols.h + * </p> + */ + public static final int JAWT_OSX_CALAYER_QUIRK_LAYOUT = 1 << 2; + + /** + * Returns bitfield of required JAWT OSX CALayer quirks to mediate AWT impl. bugs. + * <p> + * Returns zero, if platform is not {@link Platform.OSType#MACOS} + * or not supporting CALayer, i.e. OSX < 10.6.4. + * </p> + * <p> + * Otherwise includes + * <ul> + * <li>{@link #JAWT_OSX_CALAYER_QUIRK_SIZE} (always)</li> + * <li>{@link #JAWT_OSX_CALAYER_QUIRK_POSITION} if JVM < 1.7.0_40</li> + * <li>{@link #JAWT_OSX_CALAYER_QUIRK_LAYOUT} if JVM >= 1.7.0_40</li> + * </ul> + * </p> + */ + public static int getOSXCALayerQuirks() { + int res = 0; + if( PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && + PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0 ) { + + /** Knowing impl. all expose the SIZE bug */ + res |= JAWT_OSX_CALAYER_QUIRK_SIZE; + + final int c = PlatformPropsImpl.JAVA_VERSION_NUMBER.compareTo(PlatformPropsImpl.Version17); + if( c < 0 || c == 0 && PlatformPropsImpl.JAVA_VERSION_UPDATE < 40 ) { + res |= JAWT_OSX_CALAYER_QUIRK_POSITION; + } else { + res |= JAWT_OSX_CALAYER_QUIRK_LAYOUT; + } + } + return res; + } + /** * @param useOffscreenLayerIfAvailable * @return */ - public static JAWT getJAWT(boolean useOffscreenLayerIfAvailable) { - final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; - JAWT jawt = JAWT.create(); - + public static JAWT getJAWT(final boolean useOffscreenLayerIfAvailable) { + final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; + final JAWT jawt = JAWT.create(); + // default queries boolean tryOffscreenLayer; boolean tryOnscreen; int jawt_version_flags_offscreen = jawt_version_flags; - + if(isOffscreenLayerRequired()) { - if(Platform.OS_TYPE == Platform.OSType.MACOS) { - if(Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0) { + if(PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) { + if(PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0) { jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER; tryOffscreenLayer = true; tryOnscreen = false; } else { - throw new RuntimeException("OSX: Invalid version of Java ("+Platform.JAVA_VERSION_NUMBER+") / OS X ("+Platform.OS_VERSION_NUMBER+")"); + throw new RuntimeException("OSX: Invalid version of Java ("+PlatformPropsImpl.JAVA_VERSION_NUMBER+") / OS X ("+PlatformPropsImpl.OS_VERSION_NUMBER+")"); } } else { - throw new InternalError("offscreen required, but n/a for: "+Platform.OS_TYPE); + throw new InternalError("offscreen required, but n/a for: "+PlatformPropsImpl.OS_TYPE); } } else if(useOffscreenLayerIfAvailable && isOffscreenLayerSupported()) { - if(Platform.OS_TYPE == Platform.OSType.MACOS) { + if(PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) { jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER; tryOffscreenLayer = true; tryOnscreen = true; } else { - throw new InternalError("offscreen requested and supported, but n/a for: "+Platform.OS_TYPE); + throw new InternalError("offscreen requested and supported, but n/a for: "+PlatformPropsImpl.OS_TYPE); } } else { tryOffscreenLayer = false; tryOnscreen = true; - } + } if(DEBUG) { System.err.println("JAWTUtil.getJAWT(tryOffscreenLayer "+tryOffscreenLayer+", tryOnscreen "+tryOnscreen+")"); } - - StringBuilder errsb = new StringBuilder(); + + final StringBuilder errsb = new StringBuilder(); if(tryOffscreenLayer) { errsb.append("Offscreen 0x").append(Integer.toHexString(jawt_version_flags_offscreen)); if( JAWT.getJAWT(jawt, jawt_version_flags_offscreen) ) { @@ -162,82 +292,118 @@ public class JAWTUtil { errsb.append("Onscreen 0x").append(Integer.toHexString(jawt_version_flags)); if( JAWT.getJAWT(jawt, jawt_version_flags) ) { return jawt; - } + } } throw new RuntimeException("Unable to initialize JAWT, trials: "+errsb.toString()); } - - public static boolean isJAWTUsingOffscreenLayer(JAWT jawt) { + + public static boolean isJAWTUsingOffscreenLayer(final JAWT jawt) { return 0 != ( jawt.getCachedVersion() & JAWTUtil.JAWT_MACOSX_USE_CALAYER ); } - + static { + SKIP_AWT_HIDPI = PropertyAccess.isPropertyDefined("nativewindow.awt.nohidpi", true); + if(DEBUG) { - System.err.println("JAWTUtil initialization (JAWT/JNI/..."); + System.err.println("JAWTUtil initialization (JAWT/JNI/...); SKIP_AWT_HIDPI "+SKIP_AWT_HIDPI); // Thread.dumpStack(); } - JAWTJNILibLoader.initSingleton(); - if(!JAWTJNILibLoader.loadNativeWindow("awt")) { - throw new NativeWindowException("NativeWindow AWT native library load error."); - } headlessMode = GraphicsEnvironment.isHeadless(); - boolean ok = false; - Class<?> jC = null; - Method m = null; - if (!headlessMode) { + + if( headlessMode ) { + // Headless case + jawtLockObject = null; + isQueueFlusherThread = null; + j2dExist = false; + sunToolkitAWTLockMethod = null; + sunToolkitAWTUnlockMethod = null; + hasSunToolkitAWTLock = false; + // hasSunToolkitAWTLock = false; + getScaleFactorMethod = null; + } else { + // Non-headless case + JAWTJNILibLoader.initSingleton(); // load libjawt.so + if(!NWJNILibLoader.loadNativeWindow("awt")) { // load libnativewindow_awt.so + throw new NativeWindowException("NativeWindow AWT native library load error."); + } jawtLockObject = getJAWT(false); // don't care for offscreen layer here + + boolean j2dExistTmp = false; + Class<?> java2DClass = null; + Method isQueueFlusherThreadTmp = null; try { - jC = Class.forName("jogamp.opengl.awt.Java2D"); - m = jC.getMethod("isQueueFlusherThread", (Class[])null); - ok = true; - } catch (Exception e) { + java2DClass = Class.forName("jogamp.opengl.awt.Java2D"); + isQueueFlusherThreadTmp = java2DClass.getMethod("isQueueFlusherThread", (Class[])null); + j2dExistTmp = true; + } catch (final Exception e) { } - } else { - jawtLockObject = null; // headless ! - } - isQueueFlusherThread = m; - j2dExist = ok; - - PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); - try { - final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); - d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); - d.sunToolkitAWTLockMethod.setAccessible(true); - d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); - d.sunToolkitAWTUnlockMethod.setAccessible(true); - d.ok=true; - } catch (Exception e) { - // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 + isQueueFlusherThread = isQueueFlusherThreadTmp; + j2dExist = j2dExistTmp; + + final PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + final PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); + try { + final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); + d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); + d.sunToolkitAWTLockMethod.setAccessible(true); + d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); + d.sunToolkitAWTUnlockMethod.setAccessible(true); + d.ok=true; + } catch (final Exception e) { + // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 + } + try { + final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + d.getScaleFactorMethod = gd.getClass().getDeclaredMethod("getScaleFactor"); + d.getScaleFactorMethod.setAccessible(true); + } catch (final Throwable t) {} + return d; + } + }); + sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod; + sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod; + getScaleFactorMethod = pdb1.getScaleFactorMethod; + + boolean _hasSunToolkitAWTLock = false; + if ( pdb1.ok ) { + try { + sunToolkitAWTLockMethod.invoke(null, (Object[])null); + sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); + _hasSunToolkitAWTLock = true; + } catch (final Exception e) { } - return d; - } - }); - sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod; - sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod; - - boolean _hasSunToolkitAWTLock = false; - if ( pdb1.ok ) { - try { - sunToolkitAWTLockMethod.invoke(null, (Object[])null); - sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); - _hasSunToolkitAWTLock = true; - } catch (Exception e) { } + hasSunToolkitAWTLock = _hasSunToolkitAWTLock; + // hasSunToolkitAWTLock = false; } - hasSunToolkitAWTLock = _hasSunToolkitAWTLock; - // hasSunToolkitAWTLock = false; + + jawtLock = LockFactory.createRecursiveLock(); jawtToolkitLock = new ToolkitLock() { + @Override public final void lock() { JAWTUtil.lockToolkit(); - } + } + @Override public final void unlock() { JAWTUtil.unlockToolkit(); } - }; + @Override + public final void validateLocked() throws RuntimeException { + JAWTUtil.validateLocked(); + } + @Override + public final void dispose() { + // nop + } + @Override + public String toString() { + return "JAWTToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+jawtLock.isOwner(Thread.currentThread())+", "+jawtLock+"]"; + } + }; // trigger native AWT toolkit / properties initialization Map<?,?> desktophints = null; @@ -247,8 +413,9 @@ public class JAWTUtil { } else { final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1); EventQueue.invokeAndWait(new Runnable() { + @Override public void run() { - Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + final Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if(null!=_desktophints) { desktophintsBucket.add(_desktophints); } @@ -256,9 +423,9 @@ public class JAWTUtil { }); desktophints = ( desktophintsBucket.size() > 0 ) ? desktophintsBucket.get(0) : null ; } - } catch (InterruptedException ex) { + } catch (final InterruptedException ex) { ex.printStackTrace(); - } catch (InvocationTargetException ex) { + } catch (final InvocationTargetException ex) { ex.printStackTrace(); } @@ -266,7 +433,7 @@ public class JAWTUtil { System.err.println("JAWTUtil: Has sun.awt.SunToolkit.awtLock/awtUnlock " + hasSunToolkitAWTLock); System.err.println("JAWTUtil: Has Java2D " + j2dExist); System.err.println("JAWTUtil: Is headless " + headlessMode); - int hints = ( null != desktophints ) ? desktophints.size() : 0 ; + final int hints = ( null != desktophints ) ? desktophints.size() : 0 ; System.err.println("JAWTUtil: AWT Desktop hints " + hints); System.err.println("JAWTUtil: OffscreenLayer Supported: "+isOffscreenLayerSupported()+" - Required "+isOffscreenLayerRequired()); } @@ -278,11 +445,11 @@ public class JAWTUtil { public static void initSingleton() { // just exist to ensure static init has been run } - + /** * Called by {@link NativeWindowFactory#shutdown()} */ - public static void shutdown() { + public static void shutdown() { } public static boolean hasJava2D() { @@ -294,7 +461,7 @@ public class JAWTUtil { if(j2dExist) { try { b = ((Boolean)isQueueFlusherThread.invoke(null, (Object[])null)).booleanValue(); - } catch (Exception e) {} + } catch (final Exception e) {} } return b; } @@ -304,58 +471,123 @@ public class JAWTUtil { } /** - * Locks the AWT's global ReentrantLock.<br> - * + * Locks the AWT's global ReentrantLock. + * <p> * JAWT's native Lock() function calls SunToolkit.awtLock(), - * which just uses AWT's global ReentrantLock.<br> + * which just uses AWT's global ReentrantLock. + * </p> + * <p> + * AWT locking is wrapped through a recursive lock object. + * </p> */ - private static void awtLock() { - if(hasSunToolkitAWTLock) { - try { - sunToolkitAWTLockMethod.invoke(null, (Object[])null); - } catch (Exception e) { - throw new NativeWindowException("SunToolkit.awtLock failed", e); + public static void lockToolkit() throws NativeWindowException { + jawtLock.lock(); + if( 1 == jawtLock.getHoldCount() ) { + if(!headlessMode && !isJava2DQueueFlusherThread()) { + if(hasSunToolkitAWTLock) { + try { + sunToolkitAWTLockMethod.invoke(null, (Object[])null); + } catch (final Exception e) { + throw new NativeWindowException("SunToolkit.awtLock failed", e); + } + } else { + jawtLockObject.Lock(); + } } - } else { - jawtLockObject.Lock(); } + if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock(): "+jawtLock); } } /** - * Unlocks the AWT's global ReentrantLock.<br> - * + * Unlocks the AWT's global ReentrantLock. + * <p> * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), - * which just uses AWT's global ReentrantLock.<br> + * which just uses AWT's global ReentrantLock. + * </p> + * <p> + * AWT unlocking is wrapped through a recursive lock object. + * </p> */ - private static void awtUnlock() { - if(hasSunToolkitAWTLock) { - try { - sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); - } catch (Exception e) { - throw new NativeWindowException("SunToolkit.awtUnlock failed", e); + public static void unlockToolkit() { + jawtLock.validateLocked(); + if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock(): "+jawtLock); } + if( 1 == jawtLock.getHoldCount() ) { + if(!headlessMode && !isJava2DQueueFlusherThread()) { + if(hasSunToolkitAWTLock) { + try { + sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); + } catch (final Exception e) { + throw new NativeWindowException("SunToolkit.awtUnlock failed", e); + } + } else { + jawtLockObject.Unlock(); + } } - } else { - jawtLockObject.Unlock(); } + jawtLock.unlock(); } - public static void lockToolkit() throws NativeWindowException { - if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock()"); } - if(!headlessMode && !isJava2DQueueFlusherThread()) { - awtLock(); - } - } - - public static void unlockToolkit() { - if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock()"); } - if(!headlessMode && !isJava2DQueueFlusherThread()) { - awtUnlock(); - } + public static final void validateLocked() throws RuntimeException { + jawtLock.validateLocked(); } public static ToolkitLock getJAWTToolkitLock() { return jawtToolkitLock; } - + + /** + * Returns the pixel scale factor of the given {@link GraphicsDevice}, if supported. + * <p> + * If the component does not support pixel scaling the default + * <code>one</code> is returned. + * </p> + * <p> + * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays + * </p> + * @param device the {@link GraphicsDevice} instance used to query the pixel scale + * @return the pixel scale factor + */ + public static final int getPixelScale(final GraphicsDevice device) { + if( !SKIP_AWT_HIDPI ) { + if( null != getScaleFactorMethod ) { + try { + final Object res = getScaleFactorMethod.invoke(device); + if (res instanceof Integer) { + return ((Integer)res).intValue(); + } + } catch (final Throwable t) {} + } + } + return 1; + } + + /** + * Returns the pixel scale factor of the given {@link GraphicsConfiguration}'s {@link GraphicsDevice}, if supported. + * <p> + * If the {@link GraphicsDevice} is <code>null</code>, <code>zero</code> is returned. + * </p> + * <p> + * If the component does not support pixel scaling the default + * <code>one</code> is returned. + * </p> + * <p> + * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays + * </p> + * @param gc the {@link GraphicsConfiguration} instance used to query the pixel scale + * @return the pixel scale factor + */ + public static final int getPixelScale(final GraphicsConfiguration gc) { + final GraphicsDevice device = null != gc ? gc.getDevice() : null; + final int ps; + if( null == device ) { + ps = 0; + } else { + ps = JAWTUtil.getPixelScale(device); + } + if( DEBUG ) { + System.err.println("JAWTUtil.updatePixelScale: Fetched "+ps); + } + return ps; + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java index 40d7b8032..4f12d1925 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2003 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 @@ -28,11 +28,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index 5fd242247..fae8db52a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,30 +29,35 @@ * 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. */ package jogamp.nativewindow.jawt.macosx; +import java.awt.Component; import java.nio.Buffer; import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.util.Point; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.nativewindow.awt.JAWTWindow; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.awt.AWTMisc; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; import jogamp.nativewindow.jawt.JAWTUtil; @@ -62,72 +67,191 @@ import jogamp.nativewindow.jawt.macosx.JAWT_MacOSXDrawingSurfaceInfo; import jogamp.nativewindow.macosx.OSXUtil; public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { - public MacOSXJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + /** May lead to deadlock, due to AWT pos comparison .. don't enable for Applets! */ + private static final boolean DEBUG_CALAYER_POS_CRITICAL; + + static { + Debug.initSingleton(); + DEBUG_CALAYER_POS_CRITICAL = PropertyAccess.isPropertyDefined("nativewindow.debug.JAWT.OSXCALayerPos", true /* jnlpAlias */); + } + + public MacOSXJAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { super(comp, config); if(DEBUG) { dumpInfo(); } } + @Override protected void invalidateNative() { - offscreenSurfaceHandle=0; - offscreenSurfaceHandleSet=false; - if(isOffscreenLayerSurfaceEnabled()) { - if(0 != rootSurfaceLayerHandle) { - OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); - rootSurfaceLayerHandle = 0; - } + if(DEBUG) { + System.err.println("MacOSXJAWTWindow.invalidateNative(): osh-enabled "+isOffscreenLayerSurfaceEnabled()+ + ", osd-set "+offscreenSurfaceDrawableSet+ + ", osd "+toHexString(offscreenSurfaceDrawable)+ + ", osl "+toHexString(getAttachedSurfaceLayer())+ + ", rsl "+toHexString(rootSurfaceLayer)+ + ", wh "+toHexString(windowHandle)+" - "+Thread.currentThread().getName()); + } + offscreenSurfaceDrawable=0; + offscreenSurfaceDrawableSet=false; + if( isOffscreenLayerSurfaceEnabled() ) { if(0 != windowHandle) { OSXUtil.DestroyNSWindow(windowHandle); } + OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { + @Override + public void run() { + if( 0 != rootSurfaceLayer ) { + if( 0 != jawtSurfaceLayersHandle) { + UnsetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer); + } + OSXUtil.DestroyCALayer(rootSurfaceLayer); + rootSurfaceLayer = 0; + } + jawtSurfaceLayersHandle = 0; + } + }); } windowHandle=0; } + @Override + public void setSurfaceScale(final int[] pixelScale) { + super.setSurfaceScale(pixelScale); + if( 0 != getWindowHandle() ) { // locked at least once ! + final int hadPixelScaleX = getPixelScaleX(); + updatePixelScale(); + + if( hadPixelScaleX != getPixelScaleX() && 0 != getAttachedSurfaceLayer() ) { + OSXUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + final long osl = getAttachedSurfaceLayer(); + if( 0 != osl ) { + OSXUtil.SetCALayerPixelScale(rootSurfaceLayer, osl, getPixelScaleX()); + } + } + }); + } + } + } + + @Override protected void attachSurfaceLayerImpl(final long layerHandle) { - OSXUtil.AddCASublayer(rootSurfaceLayerHandle, layerHandle); + OSXUtil.RunOnMainThread(false, false /* kickNSApp */, new Runnable() { + @Override + public void run() { + // AWT position is top-left w/ insets, where CALayer position is bottom/left from root CALayer w/o insets. + // Determine p0: components location on screen w/o insets. + // CALayer position will be determined in native code. + // See detailed description in {@link JAWTUtil#JAWT_OSX_CALAYER_QUIRK_LAYOUT} + final Point p0 = new Point(); + final Component outterComp = getLocationOnScreenNonBlocking(p0, component); + final java.awt.Insets outterInsets = AWTMisc.getInsets(outterComp, true); + final Point p1 = (Point)p0.cloneMutable(); + p1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + p1.translate(-outterInsets.left, -outterInsets.top); + } + + if( DEBUG_CALAYER_POS_CRITICAL ) { + final java.awt.Point pA0 = component.getLocationOnScreen(); + final Point pA1 = new Point(pA0.x, pA0.y); + pA1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + pA1.translate(-outterInsets.left, -outterInsets.top); + } + System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], pA "+pA0+" -> "+pA1+ + ", p0 "+p0+" -> "+p1+", bounds "+bounds); + } else if( DEBUG ) { + System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds); + } + // HiDPI: uniform pixel scale + OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), getPixelScaleX(), JAWTUtil.getOSXCALayerQuirks()); + } } ); + } + + @Override + protected void layoutSurfaceLayerImpl(final long layerHandle, final boolean visible) { + final int caLayerQuirks = JAWTUtil.getOSXCALayerQuirks(); + // AWT position is top-left w/ insets, where CALayer position is bottom/left from root CALayer w/o insets. + // Determine p0: components location on screen w/o insets. + // CALayer position will be determined in native code. + // See detailed description in {@link JAWTUtil#JAWT_OSX_CALAYER_QUIRK_LAYOUT} + final Point p0 = new Point(); + final Component outterComp = getLocationOnScreenNonBlocking(p0, component); + final java.awt.Insets outterInsets = AWTMisc.getInsets(outterComp, true); + final Point p1 = (Point)p0.cloneMutable(); + p1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + p1.translate(-outterInsets.left, -outterInsets.top); + } + + if( DEBUG_CALAYER_POS_CRITICAL ) { + final java.awt.Point pA0 = component.getLocationOnScreen(); + final Point pA1 = new Point(pA0.x, pA0.y); + pA1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + pA1.translate(-outterInsets.left, -outterInsets.top); + } + System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", quirks "+caLayerQuirks+", visible "+visible+ + ", [ins "+outterInsets+"], pA "+pA0+" -> "+pA1+ + ", p0 "+p0+" -> "+p1+", bounds "+bounds); + } else if( DEBUG ) { + System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", quirks "+caLayerQuirks+", visible "+visible+ + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds); + } + OSXUtil.FixCALayerLayout(rootSurfaceLayer, layerHandle, visible, p1.getX(), p1.getY(), getWidth(), getHeight(), caLayerQuirks); } - - protected void detachSurfaceLayerImpl(final long layerHandle) { - OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle); + + @Override + protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) { + OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { + @Override + public void run() { + detachNotify.run(); + OSXUtil.RemoveCASublayer(rootSurfaceLayer, layerHandle); + } }); } - + @Override public final long getWindowHandle() { return windowHandle; } - + @Override public final long getSurfaceHandle() { - return offscreenSurfaceHandleSet ? offscreenSurfaceHandle : drawable /* super.getSurfaceHandle() */ ; + return offscreenSurfaceDrawableSet ? offscreenSurfaceDrawable : drawable /* super.getSurfaceHandle() */ ; } - - public void setSurfaceHandle(long surfaceHandle) { + + @Override + public void setSurfaceHandle(final long surfaceHandle) { if( !isOffscreenLayerSurfaceEnabled() ) { throw new java.lang.UnsupportedOperationException("Not using CALAYER"); } if(DEBUG) { - System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): "+toHexString(surfaceHandle)); } - this.offscreenSurfaceHandle = surfaceHandle; - this.offscreenSurfaceHandleSet = true; + this.offscreenSurfaceDrawable = surfaceHandle; + this.offscreenSurfaceDrawableSet = true; } + @Override protected JAWT fetchJAWTImpl() throws NativeWindowException { // use offscreen if supported and [ applet or requested ] return JAWTUtil.getJAWT(getShallUseOffscreenLayer() || isApplet()); } + + @Override protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SURFACE_NOT_READY; - if(null == ds) { - ds = getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } + int ret = NativeSurface.LOCK_SURFACE_NOT_READY; + ds = getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + unlockSurfaceImpl(); + return NativeSurface.LOCK_SURFACE_NOT_READY; } - int res = ds.Lock(); + final int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; if (!dsLocked) { unlockSurfaceImpl(); @@ -139,25 +263,24 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { // conditions can cause this code to be triggered -- should test // more) if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { - ret = NativeWindow.LOCK_SURFACE_CHANGED; + ret = NativeSurface.LOCK_SURFACE_CHANGED; } - if(null == dsi) { - if (firstLock) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - dsi = ds.GetDrawingSurfaceInfo(); - return null; - } - }); - } else { - dsi = ds.GetDrawingSurfaceInfo(); - } - if (dsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } + if (firstLock) { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + dsi = ds.GetDrawingSurfaceInfo(); + return null; + } + }); + } else { + dsi = ds.GetDrawingSurfaceInfo(); } - updateBounds(dsi.getBounds()); + if (dsi == null) { + unlockSurfaceImpl(); + return NativeSurface.LOCK_SURFACE_NOT_READY; + } + updateLockedData(dsi.getBounds()); if (DEBUG && firstLock ) { dumpInfo(); } @@ -166,24 +289,24 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (macosxdsi == null) { unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + return NativeSurface.LOCK_SURFACE_NOT_READY; } drawable = macosxdsi.getCocoaViewRef(); - + if (drawable == 0) { unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + return NativeSurface.LOCK_SURFACE_NOT_READY; } else { windowHandle = OSXUtil.GetNSWindow(drawable); - ret = NativeWindow.LOCK_SUCCESS; + ret = NativeSurface.LOCK_SUCCESS; } } else { /** * Only create a fake invisible NSWindow for the drawable handle * to please frameworks requiring such (eg. NEWT). - * - * The actual surface/ca-layer shall be created/attached - * by the upper framework (JOGL) since they require more information. + * + * The actual surface/ca-layer shall be created/attached + * by the upper framework (JOGL) since they require more information. */ String errMsg = null; if(0 == drawable) { @@ -193,31 +316,44 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } else { drawable = OSXUtil.GetNSView(windowHandle); if(0 == drawable) { - errMsg = "Null NSView of NSWindow 0x"+Long.toHexString(windowHandle); + errMsg = "Null NSView of NSWindow "+toHexString(windowHandle); } } if(null == errMsg) { - // fix caps reflecting offscreen! (no GL available here ..) - Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + // Fix caps reflecting offscreen! (no GL available here ..) + final Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); caps.setOnscreen(false); setChosenCapabilities(caps); } } if(null == errMsg) { - if(0 == rootSurfaceLayerHandle) { - rootSurfaceLayerHandle = OSXUtil.CreateCALayer(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); - if(0 == rootSurfaceLayerHandle) { - errMsg = "Could not create root CALayer"; - } else if(!SetJAWTRootSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) { - errMsg = "Could not set JAWT rootSurfaceLayerHandle 0x"+Long.toHexString(rootSurfaceLayerHandle); - } - } + jawtSurfaceLayersHandle = GetJAWTSurfaceLayersHandle0(dsi.getBuffer()); + OSXUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + String errMsg = null; + if(0 == rootSurfaceLayer && 0 != jawtSurfaceLayersHandle) { + rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight(), getPixelScaleX()); // HiDPI: uniform pixel scale + if(0 == rootSurfaceLayer) { + errMsg = "Could not create root CALayer"; + } else { + try { + SetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer); + } catch(final Exception e) { + errMsg = "Could not set JAWT rootSurfaceLayerHandle "+toHexString(rootSurfaceLayer)+", cause: "+e.getMessage(); + } + } + if(null != errMsg) { + if(0 != rootSurfaceLayer) { + OSXUtil.DestroyCALayer(rootSurfaceLayer); + rootSurfaceLayer = 0; + } + throw new NativeWindowException(errMsg+": "+MacOSXJAWTWindow.this); + } + } + } } ); } if(null != errMsg) { - if(0 != rootSurfaceLayerHandle) { - OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); - rootSurfaceLayerHandle = 0; - } if(0 != windowHandle) { OSXUtil.DestroyNSWindow(windowHandle); windowHandle = 0; @@ -226,12 +362,13 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { unlockSurfaceImpl(); throw new NativeWindowException(errMsg+": "+this); } - ret = NativeWindow.LOCK_SUCCESS; + ret = NativeSurface.LOCK_SUCCESS; } - + return ret; } - + + @Override protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -250,7 +387,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { System.err.println("MaxOSXJAWTWindow: 0x"+Integer.toHexString(this.hashCode())+" - thread: "+Thread.currentThread().getName()); dumpJAWTInfo(); } - + /** * {@inheritDoc} * <p> @@ -260,32 +397,48 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { * .. * ds = getJAWT().GetDrawingSurface(component); * due to a SIGSEGV. - * + * * Hence we have some threading / sync issues with the native JAWT implementation. - * </p> + * </p> */ @Override - public Point getLocationOnScreen(Point storage) { - return getLocationOnScreenNonBlocking(storage, component); - } + public Point getLocationOnScreen(Point storage) { + if( null == storage ) { + storage = new Point(); + } + getLocationOnScreenNonBlocking(storage, component); + return storage; + } + @Override protected Point getLocationOnScreenNativeImpl(final int x0, final int y0) { return null; } - private static native boolean SetJAWTRootSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); - // private static native boolean UnsetJAWTRootSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); - + + private static native long GetJAWTSurfaceLayersHandle0(Buffer jawtDrawingSurfaceInfoBuffer); + + /** + * Set the given root CALayer in the JAWT surface + */ + private static native void SetJAWTRootSurfaceLayer0(long jawtSurfaceLayersHandle, long caLayer); + + /** + * Unset the given root CALayer in the JAWT surface, passing the NIO DrawingSurfaceInfo buffer + */ + private static native void UnsetJAWTRootSurfaceLayer0(long jawtSurfaceLayersHandle, long caLayer); + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; - + private long jawtSurfaceLayersHandle; + private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; - - private long rootSurfaceLayerHandle = 0; // attached to the JAWT_SurfaceLayer - + + private volatile long rootSurfaceLayer = 0; // attached to the JAWT_SurfaceLayer + private long windowHandle = 0; - private long offscreenSurfaceHandle = 0; - private boolean offscreenSurfaceHandleSet = false; - + private long offscreenSurfaceDrawable = 0; + private boolean offscreenSurfaceDrawableSet = false; + // Workaround for instance of 4796548 private boolean firstLock = true; diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java index 74dabb67f..5d191f7e5 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,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. */ @@ -65,6 +65,7 @@ public class Win32SunJDKReflection { static { AccessController.doPrivileged(new PrivilegedAction() { + @Override public Object run() { try { win32GraphicsDeviceClass = Class.forName("sun.awt.Win32GraphicsDevice"); @@ -74,7 +75,7 @@ public class Win32SunJDKReflection { win32GraphicsConfigGetVisualMethod = win32GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); win32GraphicsConfigGetVisualMethod.setAccessible(true); initted = true; - } catch (Exception e) { + } catch (final Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } return null; @@ -82,37 +83,37 @@ public class Win32SunJDKReflection { }); } - public static GraphicsConfiguration graphicsConfigurationGet(GraphicsDevice device, int pfdID) { + public static GraphicsConfiguration graphicsConfigurationGet(final GraphicsDevice device, final int pfdID) { if (!initted) { return null; } try { - return (GraphicsConfiguration) win32GraphicsConfigGetConfigMethod.invoke(null, new Object[] { device, new Integer(pfdID) }); - } catch (Exception e) { + return (GraphicsConfiguration) win32GraphicsConfigGetConfigMethod.invoke(null, new Object[] { device, Integer.valueOf(pfdID) }); + } catch (final Exception e) { return null; } } - public static int graphicsConfigurationGetPixelFormatID(AbstractGraphicsConfiguration config) { + public static int graphicsConfigurationGetPixelFormatID(final AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; - } catch (Exception e) { + } catch (final Exception e) { return 0; } } - public static int graphicsConfigurationGetPixelFormatID(GraphicsConfiguration config) { + public static int graphicsConfigurationGetPixelFormatID(final GraphicsConfiguration config) { if (!initted) { return 0; } try { return ((Integer) win32GraphicsConfigGetVisualMethod.invoke(config, (Object[])null)).intValue(); - } catch (Exception e) { + } catch (final Exception e) { return 0; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 5d1d43792..7ad914e0a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,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. */ @@ -41,6 +41,7 @@ package jogamp.nativewindow.jawt.windows; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; @@ -56,34 +57,30 @@ import jogamp.nativewindow.windows.GDIUtil; public class WindowsJAWTWindow extends JAWTWindow { - public WindowsJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + public WindowsJAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { super(comp, config); } + @Override protected void invalidateNative() { windowHandle = 0; } - protected void attachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected void detachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - + @Override protected JAWT fetchJAWTImpl() throws NativeWindowException { return JAWTUtil.getJAWT(false); // no offscreen } - + + @Override protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; + int ret = NativeSurface.LOCK_SUCCESS; ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - int res = ds.Lock(); + final int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; if (!dsLocked) { unlockSurfaceImpl(); @@ -102,7 +99,7 @@ public class WindowsJAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - updateBounds(dsi.getBounds()); + updateLockedData(dsi.getBounds()); win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (win32dsi == null) { unlockSurfaceImpl(); @@ -117,6 +114,7 @@ public class WindowsJAWTWindow extends JAWTWindow { return ret; } + @Override protected void unlockSurfaceImpl() throws NativeWindowException { drawable = 0; // invalid HDC if(null!=ds) { @@ -138,7 +136,8 @@ public class WindowsJAWTWindow extends JAWTWindow { return windowHandle; } - protected Point getLocationOnScreenNativeImpl(int x, int y) { + @Override + protected Point getLocationOnScreenNativeImpl(final int x, final int y) { return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 736718de8..9abaed731 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,7 +29,7 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. @@ -38,6 +38,7 @@ package jogamp.nativewindow.jawt.x11; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; @@ -53,32 +54,28 @@ import jogamp.nativewindow.x11.X11Lib; public class X11JAWTWindow extends JAWTWindow { - public X11JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + public X11JAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { super(comp, config); } + @Override protected void invalidateNative() { } - protected void attachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected void detachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - + @Override protected JAWT fetchJAWTImpl() throws NativeWindowException { return JAWTUtil.getJAWT(false); // no offscreen } - + + @Override protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; + int ret = NativeSurface.LOCK_SUCCESS; ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - int res = ds.Lock(); + final int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; if (!dsLocked) { unlockSurfaceImpl(); @@ -97,7 +94,7 @@ public class X11JAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - updateBounds(dsi.getBounds()); + updateLockedData(dsi.getBounds()); x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (x11dsi == null) { unlockSurfaceImpl(); @@ -111,6 +108,7 @@ public class X11JAWTWindow extends JAWTWindow { return ret; } + @Override protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -126,14 +124,16 @@ public class X11JAWTWindow extends JAWTWindow { x11dsi = null; } - protected Point getLocationOnScreenNativeImpl(int x, int y) { - return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + @Override + protected Point getLocationOnScreenNativeImpl(final int x, final int y) { + // surface is locked and hence the device + return X11Lib.GetRelativeLocation(getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } - + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; private JAWT_X11DrawingSurfaceInfo x11dsi; - + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java index 27e0a5e50..fea1be11a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,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. */ @@ -65,6 +65,7 @@ public class X11SunJDKReflection { static { AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { try { x11GraphicsDeviceClass = Class.forName("sun.awt.X11GraphicsDevice"); @@ -75,7 +76,7 @@ public class X11SunJDKReflection { x11GraphicsConfigGetVisualMethod = x11GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); x11GraphicsConfigGetVisualMethod.setAccessible(true); initialized = true; - } catch (Exception e) { + } catch (final Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } return null; @@ -83,37 +84,37 @@ public class X11SunJDKReflection { }); } - public static long graphicsDeviceGetDisplay(GraphicsDevice device) { + public static long graphicsDeviceGetDisplay(final GraphicsDevice device) { if (!initialized) { return 0; } try { return ((Long) x11GraphicsDeviceGetDisplayMethod.invoke(device, (Object[])null)).longValue(); - } catch (Exception e) { + } catch (final Exception e) { return 0; } } - public static int graphicsConfigurationGetVisualID(AbstractGraphicsConfiguration config) { + public static int graphicsConfigurationGetVisualID(final AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; - } catch (Exception e) { + } catch (final Exception e) { return 0; } } - public static int graphicsConfigurationGetVisualID(GraphicsConfiguration config) { + public static int graphicsConfigurationGetVisualID(final GraphicsConfiguration config) { if (!initialized) { return 0; } try { return ((Integer) x11GraphicsConfigGetVisualMethod.invoke(config, (Object[])null)).intValue(); - } catch (Exception e) { + } catch (final Exception e) { return 0; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java index de3206c0c..6b54c32ea 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java @@ -9,39 +9,39 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; public class OSXDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { long nsWindow; - + /** - * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, - * not the actual dummy surface width. + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. * The latter is platform specific and small - * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, * not the actual dummy surface height, * The latter is platform specific and small */ - public OSXDummyUpstreamSurfaceHook(int width, int height) { + public OSXDummyUpstreamSurfaceHook(final int width, final int height) { super(width, height); nsWindow = 0; } - + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { if(0 == nsWindow && 0 == s.getSurfaceHandle()) { nsWindow = OSXUtil.CreateNSWindow(0, 0, 64, 64); if(0 == nsWindow) { throw new NativeWindowException("Error NS window 0"); } - long nsView = OSXUtil.GetNSView(nsWindow); + final long nsView = OSXUtil.GetNSView(nsWindow); if(0 == nsView) { throw new NativeWindowException("Error NS view 0"); } s.setSurfaceHandle(nsView); - s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); } - + @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { if( 0 == nsWindow || 0 == s.getSurfaceHandle() ) { throw new InternalError("Owns upstream surface, but no OSX view/window: "+s+", nsWindow 0x"+Long.toHexString(nsWindow)); diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index b7a83e133..cf163bd82 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -32,15 +32,24 @@ import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; +import com.jogamp.common.util.Function; +import com.jogamp.common.util.FunctionTask; +import com.jogamp.common.util.RunnableTask; + import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; -public class OSXUtil { - private static boolean isInit = false; +public class OSXUtil implements ToolkitProperties { + private static boolean isInit = false; private static final boolean DEBUG = Debug.debug("OSXUtil"); - + + /** FIXME HiDPI: OSX unique and maximum value {@value} */ + public static final int MAX_PIXELSCALE = 2; + /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static synchronized void initSingleton() { if(!isInit) { @@ -50,121 +59,318 @@ public class OSXUtil { if(!NWJNILibLoader.loadNativeWindow("macosx")) { throw new NativeWindowException("NativeWindow MacOSX native library load error."); } - + if( !initIDs0() ) { throw new NativeWindowException("MacOSX: Could not initialized native stub"); - } + } isInit = true; } } /** * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties */ - public static void shutdown() { - } - - public static boolean requiresToolkitLock() { - return false; - } - - public static boolean isNSView(long object) { - return isNSView0(object); + public static void shutdown() { } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static boolean requiresToolkitLock() { return false; } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { return false; } + + public static boolean isNSView(final long object) { + return 0 != object ? isNSView0(object) : false; } - - public static boolean isNSWindow(long object) { - return isNSWindow0(object); + + public static boolean isNSWindow(final long object) { + return 0 != object ? isNSWindow0(object) : false; } - + /** - * In case the <code>windowOrView</code> is top-level, - * you shall set <code>topLevel</code> to true where - * insets gets into account to compute the client position as follows: - * <pre> - if(topLevel) { - // top-level position -> client window position - final Insets insets = GetInsets(windowOrView); - los.setX(los.getX() + insets.getLeftWidth()); - los.setY(los.getY() + insets.getTopHeight()); - } - * </pre> * @param windowOrView - * @param topLevel * @param src_x * @param src_y - * @return the client position + * @return top-left client-area position in window units */ - public static Point GetLocationOnScreen(long windowOrView, boolean topLevel, int src_x, int src_y) { - final Point los = (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); - if(topLevel) { - // top-level position -> client window position - final Insets insets = GetInsets(windowOrView); - los.setX(los.getX() + insets.getLeftWidth()); - los.setY(los.getY() + insets.getTopHeight()); - } - return los; + public static Point GetLocationOnScreen(final long windowOrView, final int src_x, final int src_y) { + return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); } - - public static Insets GetInsets(long windowOrView) { + + public static Insets GetInsets(final long windowOrView) { return (Insets) GetInsets0(windowOrView); } - - public static long CreateNSWindow(int x, int y, int width, int height) { + + public static double GetPixelScale(final int screenIndex) { + return GetPixelScale0(screenIndex); + } + + public static double GetPixelScale(final long windowOrView) { + return GetPixelScale1(windowOrView); + } + + public static long CreateNSWindow(final int x, final int y, final int width, final int height) { return CreateNSWindow0(x, y, width, height); } - public static void DestroyNSWindow(long nsWindow) { + public static void DestroyNSWindow(final long nsWindow) { DestroyNSWindow0(nsWindow); } - public static long GetNSView(long nsWindow) { + public static long GetNSView(final long nsWindow) { return GetNSView0(nsWindow); } - public static long GetNSWindow(long nsView) { + public static long GetNSWindow(final long nsView) { return GetNSWindow0(nsView); } - - public static long CreateCALayer(int x, int y, int width, int height) { - return CreateCALayer0(x, y, width, height); + + /** + * Create a CALayer suitable to act as a root CALayer. + * @param width width of the CALayer in window units (points) + * @param height height of the CALayer in window units (points) + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + * @return the new CALayer object + * @see #DestroyCALayer(long) + * @see #AddCASublayer(long, long) + */ + public static long CreateCALayer(final int width, final int height, final float contentsScale) { + final long l = CreateCALayer0(width, height, contentsScale); + if(DEBUG) { + System.err.println("OSXUtil.CreateCALayer: 0x"+Long.toHexString(l)+" - "+Thread.currentThread().getName()); + } + return l; } - public static void AddCASublayer(long rootCALayer, long subCALayer) { + + /** + * Attach a sub CALayer to the root CALayer + * <p> + * Method will trigger a <code>display</code> + * call to the CALayer hierarchy to enforce resource creation if required, e.g. an NSOpenGLContext. + * </p> + * <p> + * Hence it is important that related resources are not locked <i>if</i> + * they will be used for creation. + * </p> + * @param rootCALayer + * @param subCALayer + * @param x x-coord of the sub-CALayer in window units (points) + * @param y y-coord of the sub-CALayer in window units (points) + * @param width width of the sub-CALayer in window units (points) + * @param height height of the sub-CALayer in window units (points) + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + * @param caLayerQuirks + * @see #CreateCALayer(int, int, float) + * @see #RemoveCASublayer(long, long, boolean) + */ + public static void AddCASublayer(final long rootCALayer, final long subCALayer, + final int x, final int y, final int width, final int height, + final float contentsScale, final int caLayerQuirks) { if(0==rootCALayer || 0==subCALayer) { throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); } - AddCASublayer0(rootCALayer, subCALayer); + if(DEBUG) { + System.err.println("OSXUtil.AttachCALayer: caLayerQuirks "+caLayerQuirks+", 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName()); + } + AddCASublayer0(rootCALayer, subCALayer, x, y, width, height, contentsScale, caLayerQuirks); + } + + /** + * Fix root and sub CALayer position to 0/0 and size + * <p> + * If the sub CALayer implements the Objective-C NativeWindow protocol NWDedicatedSize (e.g. JOGL's MyNSOpenGLLayer), + * the dedicated size is passed to the layer, which propagates it appropriately. + * </p> + * <p> + * On OSX/Java7 our root CALayer's frame position and size gets corrupted by its NSView, + * hence we have created the NWDedicatedSize protocol. + * </p> + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param visible TODO + * @param width the expected width in window units (points) + * @param height the expected height in window units (points) + * @param caLayerQuirks TODO + */ + public static void FixCALayerLayout(final long rootCALayer, final long subCALayer, final boolean visible, final int x, final int y, final int width, final int height, final int caLayerQuirks) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + FixCALayerLayout0(rootCALayer, subCALayer, visible, x, y, width, height, caLayerQuirks); + } + + /** + * Set root and sub CALayer pixelScale / contentScale for HiDPI + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static void SetCALayerPixelScale(final long rootCALayer, final long subCALayer, final float contentsScale) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + SetCALayerPixelScale0(rootCALayer, subCALayer, contentsScale); } - public static void RemoveCASublayer(long rootCALayer, long subCALayer) { + + /** + * Detach a sub CALayer from the root CALayer. + */ + public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) { if(0==rootCALayer || 0==subCALayer) { throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); } + if(DEBUG) { + System.err.println("OSXUtil.DetachCALayer: 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName()); + } RemoveCASublayer0(rootCALayer, subCALayer); } - public static void DestroyCALayer(long caLayer) { + + /** + * Destroy a CALayer. + * @see #CreateCALayer(int, int, float) + */ + public static void DestroyCALayer(final long caLayer) { if(0==caLayer) { throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); } - DestroyCALayer0(caLayer); + if(DEBUG) { + System.err.println("OSXUtil.DestroyCALayer: 0x"+Long.toHexString(caLayer)+" - "+Thread.currentThread().getName()); + } + DestroyCALayer0(caLayer); } - - public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) { - if(IsMainThread0()) { + + /** + * Run on OSX UI main thread. + * <p> + * 'waitUntilDone' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread. + * </p> + * + * @param waitUntilDone + * @param kickNSApp if <code>true</code> issues {@link #KickNSApp()} + * @param runnable + */ + public static void RunOnMainThread(final boolean waitUntilDone, final boolean kickNSApp, final Runnable runnable) { + if( IsMainThread0() ) { runnable.run(); // don't leave the JVM } else { - RunOnMainThread0(waitUntilDone, runnable); + // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, + // otherwise we may freeze the OSX main thread. + Throwable throwable = null; + final Object sync = new Object(); + final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); + synchronized(sync) { + RunOnMainThread0(kickNSApp, rt); + if( waitUntilDone ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rt.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + } + } + + /** + * Run later on .. + * @param onMain if true, run on main-thread, otherwise on the current OSX thread. + * @param runnable + * @param delay delay to run the runnable in milliseconds + */ + public static void RunLater(final boolean onMain, final Runnable runnable, final int delay) { + RunLater0(onMain, false /* kickNSApp */, new RunnableTask( runnable, null, true, System.err ), delay); + } + + /** + * Wakes up NSApp thread by sending an empty NSEvent .. + * <p> + * This is deemed important <i>sometimes</i> where resources shall get freed ASAP, e.g. GL context etc. + * </p> + * <p> + * The following scenarios requiring this <i>wake-up</i> are currently known: + * <ul> + * <li>Destruction of an OpenGL context</li> + * <li>Destruction of Windows .. ?</li> + * <li>Stopping the NSApp</li> + * </ul> + * </p> + * FIXME: Complete list of scenarios and reason it. + */ + public static void KickNSApp() { + KickNSApp0(); + } + + private static Runnable _nop = new Runnable() { @Override public void run() {}; }; + + /** Issues a {@link #RunOnMainThread(boolean, boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done and issuing {@link #KickNSApp()}. */ + public static void WaitUntilFinish() { + RunOnMainThread(true, true /* kickNSApp */, _nop); + } + + /** + * Run on OSX UI main thread. + * <p> + * 'waitUntilDone' is implemented on Java site via lock/wait on {@link FunctionTask} to not freeze OSX main thread. + * </p> + * + * @param waitUntilDone + * @param kickNSApp if <code>true</code> issues {@link #KickNSApp()} + * @param func + */ + public static <R,A> R RunOnMainThread(final boolean waitUntilDone, final boolean kickNSApp, final Function<R,A> func, final A... args) { + if( IsMainThread0() ) { + return func.eval(args); // don't leave the JVM + } else { + // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, + // otherwise we may freeze the OSX main thread. + Throwable throwable = null; + final Object sync = new Object(); + final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); + synchronized(sync) { + rt.setArgs(args); + RunOnMainThread0(kickNSApp, rt); + if( waitUntilDone ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rt.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + return rt.getResult(); } } - + public static boolean IsMainThread() { return IsMainThread0(); } - + /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */ - public static int GetScreenRefreshRate(int scrn_idx) { + public static int GetScreenRefreshRate(final int scrn_idx) { return GetScreenRefreshRate0(scrn_idx); } - + /*** private static boolean isAWTEDTMainThreadInit = false; private static boolean isAWTEDTMainThread; - + public synchronized static boolean isAWTEDTMainThread() { if(!isAWTEDTMainThreadInit) { isAWTEDTMainThreadInit = true; @@ -178,24 +384,30 @@ public class OSXUtil { } else { isAWTEDTMainThread = false; } - } + } return isAWTEDTMainThread; } */ - + private static native boolean initIDs0(); private static native boolean isNSView0(long object); private static native boolean isNSWindow0(long object); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); private static native Object GetInsets0(long windowOrView); + private static native double GetPixelScale0(int screenIndex); + private static native double GetPixelScale1(long windowOrView); private static native long CreateNSWindow0(int x, int y, int width, int height); private static native void DestroyNSWindow0(long nsWindow); private static native long GetNSView0(long nsWindow); private static native long GetNSWindow0(long nsView); - private static native long CreateCALayer0(int x, int y, int width, int height); - private static native void AddCASublayer0(long rootCALayer, long subCALayer); + private static native long CreateCALayer0(int width, int height, float contentsScale); + private static native void AddCASublayer0(long rootCALayer, long subCALayer, int x, int y, int width, int height, float contentsScale, int caLayerQuirks); + private static native void FixCALayerLayout0(long rootCALayer, long subCALayer, boolean visible, int x, int y, int width, int height, int caLayerQuirks); + private static native void SetCALayerPixelScale0(long rootCALayer, long subCALayer, float contentsScale); private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); private static native void DestroyCALayer0(long caLayer); - private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable); + private static native void RunOnMainThread0(boolean kickNSApp, Runnable runnable); + private static native void RunLater0(boolean onMain, boolean kickNSApp, Runnable runnable, int delay); + private static native void KickNSApp0(); private static native boolean IsMainThread0(); private static native int GetScreenRefreshRate0(int scrn_idx); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java index aa5f3dac5..a08cf9b51 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java @@ -9,33 +9,33 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { /** - * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, - * not the actual dummy surface width. + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. * The latter is platform specific and small - * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, * not the actual dummy surface height, * The latter is platform specific and small */ - public GDIDummyUpstreamSurfaceHook(int width, int height) { + public GDIDummyUpstreamSurfaceHook(final int width, final int height) { super(width, height); } - + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { final GDISurface ms = (GDISurface)s; - if(0 == ms.getWindowHandle()) { + if(0 == ms.getWindowHandle()) { final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, 64, 64); if(0 == windowHandle) { throw new NativeWindowException("Error windowHandle 0, werr: "+GDI.GetLastError()); - } + } ms.setWindowHandle(windowHandle); - ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); } - + @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { final GDISurface ms = (GDISurface)s; if( ms.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { if( 0 == ms.getWindowHandle() ) { @@ -46,5 +46,5 @@ public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize ms.setWindowHandle(0); ms.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } - } + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java index 3db2b5fc9..2f335c428 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java @@ -43,10 +43,12 @@ import jogamp.nativewindow.windows.GDI; * allowing the use of HDC via lockSurface()/unlockSurface() protocol. * The latter will get and release the HDC. * The size via getWidth()/getHeight() is invalid. + * + * @see ProxySurface */ public class GDISurface extends ProxySurfaceImpl { - protected long windowHandle; - protected long surfaceHandle; + private long windowHandle; + private long surfaceHandle; /** * @param cfg the {@link AbstractGraphicsConfiguration} to be used @@ -56,37 +58,37 @@ public class GDISurface extends ProxySurfaceImpl { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. */ - public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, UpstreamSurfaceHook upstream, boolean ownsDevice) { + public GDISurface(final AbstractGraphicsConfiguration cfg, final long windowHandle, final UpstreamSurfaceHook upstream, final boolean ownsDevice) { super(cfg, upstream, ownsDevice); this.windowHandle=windowHandle; this.surfaceHandle=0; } @Override - protected void invalidateImpl() { + protected void invalidateImpl() { if(0 != surfaceHandle) { throw new NativeWindowException("didn't release surface Handle: "+this); } windowHandle = 0; // surfaceHandle = 0; } - + /** * {@inheritDoc} * <p> - * Actually the window handle (HWND), since the surfaceHandle (HDC) is derived + * Actually the window handle (HWND), since the surfaceHandle (HDC) is derived * from it at {@link #lockSurface()}. - * </p> + * </p> */ @Override - public final void setSurfaceHandle(long surfaceHandle) { + public final void setSurfaceHandle(final long surfaceHandle) { this.windowHandle = surfaceHandle; } /** - * Sets the window handle (HWND). + * Sets the window handle (HWND). */ - public final void setWindowHandle(long windowHandle) { + public final void setWindowHandle(final long windowHandle) { this.windowHandle = windowHandle; } @@ -116,7 +118,7 @@ public class GDISurface extends ProxySurfaceImpl { final protected void unlockSurfaceImpl() { if (0 != surfaceHandle) { if(0 == GDI.ReleaseDC(windowHandle, surfaceHandle)) { - throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); + throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); } surfaceHandle=0; } @@ -126,4 +128,15 @@ public class GDISurface extends ProxySurfaceImpl { final public long getSurfaceHandle() { return surfaceHandle; } + + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + return pixelUnitsAndResult; // no pixelScale factor + } + + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + return windowUnitsAndResult; // no pixelScale factor + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java index 613c76032..c409b6a39 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -33,21 +33,22 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.Debug; -import jogamp.nativewindow.x11.X11Util; +import jogamp.nativewindow.ToolkitProperties; -public class GDIUtil { +public class GDIUtil implements ToolkitProperties { private static final boolean DEBUG = Debug.debug("GDIUtil"); - + private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ; private static RegisteredClassFactory dummyWindowClassFactory; - private static boolean isInit = false; - + private static volatile boolean isInit = false; + /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static synchronized void initSingleton() { if(!isInit) { - synchronized(X11Util.class) { + synchronized(GDIUtil.class) { if(!isInit) { if(DEBUG) { System.out.println("GDI.initSingleton()"); @@ -58,53 +59,95 @@ public class GDIUtil { if( !initIDs0() ) { throw new NativeWindowException("GDI: Could not initialized native stub"); } - dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0()); + dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0(), + true /* useDummyDispatchThread */, + 0 /* iconSmallHandle */, 0 /* iconBigHandle */); + if(DEBUG) { + System.out.println("GDI.initSingleton() dummyWindowClassFactory "+dummyWindowClassFactory); + } isInit = true; } } } } - + /** * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties */ - public static void shutdown() { + public static void shutdown() { } - + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ public static boolean requiresToolkitLock() { return false; } - + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { return false; } + private static RegisteredClass dummyWindowClass = null; private static Object dummyWindowSync = new Object(); - - public static long CreateDummyWindow(int x, int y, int width, int height) { + + public static long CreateDummyWindow(final int x, final int y, final int width, final int height) { synchronized(dummyWindowSync) { dummyWindowClass = dummyWindowClassFactory.getSharedClass(); - return CreateDummyWindow0(dummyWindowClass.getHandle(), dummyWindowClass.getName(), dummyWindowClass.getName(), x, y, width, height); + if(DEBUG) { + System.out.println("GDI.CreateDummyWindow() dummyWindowClassFactory "+dummyWindowClassFactory); + System.out.println("GDI.CreateDummyWindow() dummyWindowClass "+dummyWindowClass); + } + return CreateDummyWindow0(dummyWindowClass.getHInstance(), dummyWindowClass.getName(), dummyWindowClass.getHDispThreadContext(), dummyWindowClass.getName(), x, y, width, height); } } - - public static boolean DestroyDummyWindow(long hwnd) { + + public static boolean DestroyDummyWindow(final long hwnd) { boolean res; synchronized(dummyWindowSync) { if( null == dummyWindowClass ) { throw new InternalError("GDI Error ("+dummyWindowClassFactory.getSharedRefCount()+"): SharedClass is null"); } - res = GDI.DestroyWindow(hwnd); + res = DestroyWindow0(dummyWindowClass.getHDispThreadContext(), hwnd); dummyWindowClassFactory.releaseSharedClass(); } return res; } - - public static Point GetRelativeLocation(long src_win, long dest_win, int src_x, int src_y) { + + public static Point GetRelativeLocation(final long src_win, final long dest_win, final int src_x, final int src_y) { return (Point) GetRelativeLocation0(src_win, dest_win, src_x, src_y); } - - public static native boolean CreateWindowClass(long hInstance, String clazzName, long wndProc); - public static native boolean DestroyWindowClass(long hInstance, String className); - + + public static boolean IsUndecorated(final long win) { + return IsUndecorated0(win); + } + + public static boolean IsChild(final long win) { + return IsChild0(win); + } + + public static void SetProcessThreadsAffinityMask(final long affinityMask, final boolean verbose) { + SetProcessThreadsAffinityMask0(affinityMask, verbose); + } + + private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + + /** Creates WNDCLASSEX instance */ + static native boolean CreateWindowClass0(long hInstance, String clazzName, long wndProc, long iconSmallHandle, long iconBigHandle); + /** Destroys WNDCLASSEX instance */ + static native boolean DestroyWindowClass0(long hInstance, String className, long dispThreadCtx); + static native long CreateDummyDispatchThread0(); + private static native boolean initIDs0(); - private static native long getDummyWndProc0(); + private static native long getDummyWndProc0(); private static native Object GetRelativeLocation0(long src_win, long dest_win, int src_x, int src_y); - - static native long CreateDummyWindow0(long hInstance, String className, String windowName, int x, int y, int width, int height); + private static native boolean IsChild0(long win); + private static native boolean IsUndecorated0(long win); + + private static native void SetProcessThreadsAffinityMask0(long affinityMask, boolean verbose); + + private static native long CreateDummyWindow0(long hInstance, String className, long dispThreadCtx, String windowName, int x, int y, int width, int height); + private static native boolean DestroyWindow0(long dispThreadCtx, long win); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java index afb3daf7c..3c7b1adfb 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java @@ -29,17 +29,25 @@ package jogamp.nativewindow.windows; public class RegisteredClass { - long hInstance; - String className; + private final long hInstance; + private final String className; + private final long hDDTCtx; - RegisteredClass(long hInst, String name) { - hInstance = hInst; - className = name; + RegisteredClass(final long hInst, final String name, final long hDispatchThreadCtx) { + this.hInstance = hInst; + this.className = name; + this.hDDTCtx = hDispatchThreadCtx; } - public final long getHandle() { return hInstance; } + /** Application handle, same as {@link RegisteredClassFactory#getHInstance()}. */ + public final long getHInstance() { return hInstance; } + + /** Unique Window Class Name */ public final String getName() { return className; } + /** Unique associated dispatch thread context for this Window Class, or 0 for none. */ + public final long getHDispThreadContext() { return hDDTCtx; } + @Override - public final String toString() { return "RegisteredClass[handle 0x"+Long.toHexString(hInstance)+", "+className+"]"; } + public final String toString() { return "RegisteredClass[handle 0x"+Long.toHexString(hInstance)+", "+className+", dtx 0x"+Long.toHexString(hDDTCtx)+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java index 00bedfc8e..e3ea49314 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java @@ -29,46 +29,76 @@ package jogamp.nativewindow.windows; import jogamp.nativewindow.Debug; + import java.util.ArrayList; + import javax.media.nativewindow.NativeWindowException; public class RegisteredClassFactory { - static final boolean DEBUG = Debug.debug("RegisteredClass"); - private static ArrayList<RegisteredClassFactory> registeredFactories = new ArrayList<RegisteredClassFactory>(); - - private String classBaseName; - private long wndProc; + private static final boolean DEBUG = Debug.debug("RegisteredClass"); + private static final ArrayList<RegisteredClassFactory> registeredFactories; + private static final long hInstance; + + static { + hInstance = GDI.GetApplicationHandle(); + if( 0 == hInstance ) { + throw new NativeWindowException("Error: Null ModuleHandle for Application"); + } + registeredFactories = new ArrayList<RegisteredClassFactory>(); + } + + private final String classBaseName; + private final long wndProc; + private final boolean useDummyDispatchThread; + private final long iconSmallHandle, iconBigHandle; private RegisteredClass sharedClass = null; private int classIter = 0; private int sharedRefCount = 0; private final Object sync = new Object(); + private String toHexString(final long l) { return "0x"+Long.toHexString(l); } + + @Override + public final String toString() { return "RegisteredClassFactory[moduleHandle "+toHexString(hInstance)+", "+classBaseName+ + ", wndProc "+toHexString(wndProc)+", useDDT "+useDummyDispatchThread+", shared[refCount "+sharedRefCount+", class "+sharedClass+"]]"; } + /** - * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. + * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. */ public static void shutdownSharedClasses() { synchronized(registeredFactories) { + if( DEBUG ) { + System.err.println("RegisteredClassFactory.shutdownSharedClasses: "+registeredFactories.size()); + } for(int j=0; j<registeredFactories.size(); j++) { final RegisteredClassFactory rcf = registeredFactories.get(j); synchronized(rcf.sync) { if(null != rcf.sharedClass) { - GDIUtil.DestroyWindowClass(rcf.sharedClass.getHandle(), rcf.sharedClass.getName()); + GDIUtil.DestroyWindowClass0(rcf.sharedClass.getHInstance(), rcf.sharedClass.getName(), rcf.sharedClass.getHDispThreadContext()); rcf.sharedClass = null; rcf.sharedRefCount = 0; - rcf.classIter = 0; + rcf.classIter = 0; if(DEBUG) { - System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+" shutdownSharedClasses : "+rcf.sharedClass); + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+": shutdownSharedClasses : "+rcf.sharedClass); } + } else if(DEBUG) { + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+": null"); } } } } } - public RegisteredClassFactory(String classBaseName, long wndProc) { + /** Application handle. */ + public static long getHInstance() { return hInstance; } + + public RegisteredClassFactory(final String classBaseName, final long wndProc, final boolean useDummyDispatchThread, final long iconSmallHandle, final long iconBigHandle) { this.classBaseName = classBaseName; this.wndProc = wndProc; + this.useDummyDispatchThread = useDummyDispatchThread; + this.iconSmallHandle = iconSmallHandle; + this.iconBigHandle = iconBigHandle; synchronized(registeredFactories) { registeredFactories.add(this); } @@ -80,23 +110,28 @@ public class RegisteredClassFactory { if( null != sharedClass ) { throw new InternalError("Error ("+sharedRefCount+"): SharedClass not null: "+sharedClass); } - long hInstance = GDI.GetApplicationHandle(); - if( 0 == hInstance ) { - throw new NativeWindowException("Error: Null ModuleHandle for Application"); - } String clazzName = null; boolean registered = false; - final int classIterMark = classIter - 1; + final int classIterMark = classIter - 1; while ( !registered && classIterMark != classIter ) { // Retry with next clazz name, this could happen if more than one JVM is running clazzName = classBaseName + classIter; classIter++; - registered = GDIUtil.CreateWindowClass(hInstance, clazzName, wndProc); + registered = GDIUtil.CreateWindowClass0(hInstance, clazzName, wndProc, iconSmallHandle, iconBigHandle); } if( !registered ) { throw new NativeWindowException("Error: Could not create WindowClass: "+clazzName); } - sharedClass = new RegisteredClass(hInstance, clazzName); + final long hDispatchThread; + if( useDummyDispatchThread ) { + hDispatchThread = GDIUtil.CreateDummyDispatchThread0(); + if( 0 == hDispatchThread ) { + throw new NativeWindowException("Error: Could not create DDT "+clazzName); + } + } else { + hDispatchThread = 0; + } + sharedClass = new RegisteredClass(hInstance, clazzName, hDispatchThread); if(DEBUG) { System.err.println("RegisteredClassFactory getSharedClass ("+sharedRefCount+") initialized: "+sharedClass); } @@ -121,7 +156,7 @@ public class RegisteredClassFactory { throw new InternalError("Error ("+sharedRefCount+"): SharedClass is null"); } if( 0 == sharedRefCount ) { - GDIUtil.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); + GDIUtil.DestroyWindowClass0(sharedClass.getHInstance(), sharedClass.getName(), sharedClass.getHDispThreadContext()); if(DEBUG) { System.err.println("RegisteredClassFactory releaseSharedClass ("+sharedRefCount+") released: "+sharedClass); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java index 4f8cff8c5..0ac3d4a2e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java @@ -35,7 +35,7 @@ import javax.media.nativewindow.VisualIDHolder; public class X11Capabilities extends Capabilities { final private XVisualInfo xVisualInfo; // maybe null if !onscreen - public X11Capabilities(XVisualInfo xVisualInfo) { + public X11Capabilities(final XVisualInfo xVisualInfo) { super(); this.xVisualInfo = xVisualInfo; } @@ -49,7 +49,7 @@ public class X11Capabilities extends Capabilities { public Object clone() { try { return super.clone(); - } catch (RuntimeException e) { + } catch (final RuntimeException e) { throw new NativeWindowException(e); } } @@ -59,7 +59,7 @@ public class X11Capabilities extends Capabilities { final public boolean hasXVisualInfo() { return null!=xVisualInfo; } @Override - final public int getVisualID(VIDType type) throws NativeWindowException { + final public int getVisualID(final VIDType type) throws NativeWindowException { switch(type) { case INTRINSIC: case NATIVE: diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java index 55a29dd5e..7e61ba6d0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java @@ -14,47 +14,57 @@ import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { /** - * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, - * not the actual dummy surface width. + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. * The latter is platform specific and small - * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, * not the actual dummy surface height, * The latter is platform specific and small */ - public X11DummyUpstreamSurfaceHook(int width, int height) { + public X11DummyUpstreamSurfaceHook(final int width, final int height) { super(width, height); } - + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { final X11GraphicsConfiguration cfg = (X11GraphicsConfiguration) s.getGraphicsConfiguration(); final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen(); final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice(); - if(0 == device.getHandle()) { - device.open(); - s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); - } - if( 0 == s.getSurfaceHandle() ) { - final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64); - if(0 == windowHandle) { - throw new NativeWindowException("Creating dummy window failed w/ "+cfg); + device.lock(); + try { + if(0 == device.getHandle()) { + device.open(); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + if( 0 == s.getSurfaceHandle() ) { + final long windowHandle = X11Lib.CreateWindow(0, device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64, false, false); + if(0 == windowHandle) { + throw new NativeWindowException("Creating dummy window failed w/ "+cfg); + } + s.setSurfaceHandle(windowHandle); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } - s.setSurfaceHandle(windowHandle); - s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } finally { + device.unlock(); } - s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); } - + @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { final X11GraphicsDevice device = (X11GraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); if( 0 == s.getSurfaceHandle() ) { throw new InternalError("Owns upstream surface, but no X11 window: "+s); } - X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle()); - s.setSurfaceHandle(0); - s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + device.lock(); + try { + X11Lib.DestroyWindow(device.getHandle(), s.getSurfaceHandle()); + s.setSurfaceHandle(0); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } finally { + device.unlock(); + } } } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index b11dd1df1..e12c3fd13 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.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 @@ -47,12 +47,13 @@ import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { public static void registerFactory() { GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, CapabilitiesImmutable.class, new X11GraphicsConfigurationFactory()); - } + } private X11GraphicsConfigurationFactory() { } - + + @Override protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, final CapabilitiesChooser chooser, final AbstractGraphicsScreen screen, final int nativeVisualID) throws IllegalArgumentException, NativeWindowException { if(!(screen instanceof X11GraphicsScreen)) { @@ -71,15 +72,15 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor return res; } - public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, int visualID) + public static XVisualInfo getXVisualInfo(final AbstractGraphicsScreen screen, final int visualID) { - XVisualInfo xvi_temp = XVisualInfo.create(); + final XVisualInfo xvi_temp = XVisualInfo.create(); xvi_temp.setVisualid(visualID); xvi_temp.setScreen(screen.getIndex()); - int num[] = { -1 }; - long display = screen.getDevice().getHandle(); + final int num[] = { -1 }; + final long display = screen.getDevice().getHandle(); - XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); + final XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); if(xvis==null || num[0]<1) { return null; @@ -88,28 +89,28 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor return XVisualInfo.create(xvis[0]); } - public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, CapabilitiesImmutable capabilities) + public static XVisualInfo getXVisualInfo(final AbstractGraphicsScreen screen, final CapabilitiesImmutable capabilities) { - XVisualInfo xv = getXVisualInfoImpl(screen, capabilities, 4 /* TrueColor */); + final XVisualInfo xv = getXVisualInfoImpl(screen, capabilities, 4 /* TrueColor */); if(null!=xv) return xv; return getXVisualInfoImpl(screen, capabilities, 5 /* DirectColor */); } - private static XVisualInfo getXVisualInfoImpl(AbstractGraphicsScreen screen, CapabilitiesImmutable capabilities, int c_class) + private static XVisualInfo getXVisualInfoImpl(final AbstractGraphicsScreen screen, final CapabilitiesImmutable capabilities, final int c_class) { XVisualInfo ret = null; - int[] num = { -1 }; + final int[] num = { -1 }; - XVisualInfo vinfo_template = XVisualInfo.create(); + final XVisualInfo vinfo_template = XVisualInfo.create(); vinfo_template.setScreen(screen.getIndex()); vinfo_template.setC_class(c_class); - long display = screen.getDevice().getHandle(); + final long display = screen.getDevice().getHandle(); - XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); + final XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); XVisualInfo best=null; - int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); + final int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); for (int i = 0; vinfos!=null && i < num[0]; i++) { - if ( best == null || + if ( best == null || best.getDepth() < vinfos[i].getDepth() ) { best = vinfos[i]; diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 93b7f3487..2414248b4 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.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 @@ -34,6 +34,7 @@ package jogamp.nativewindow.x11; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; @@ -42,22 +43,27 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.common.util.PropertyAccess; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; /** * Contains a thread safe X11 utility to retrieve display connections. */ -public class X11Util { - /** +public class X11Util implements ToolkitProperties { + public static final boolean DEBUG = Debug.debug("X11Util"); + + /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 - * <p> + * <p> * It is observed that ATI X11 drivers, eg. - * <ul> + * <ul> * <li>fglrx 8.78.6,</li> * <li>fglrx 11.08/8.881 and </li> * <li>fglrx 11.11/8.911</li> - * </ul> + * </ul> * are quite sensitive to multiple Display connections. * </p> * <p> @@ -70,33 +76,39 @@ public class X11Util { * See also native test: jogl/test-native/displayMultiple02.c * </p> * <p> - * Workaround is to not close them at all if driver vendor is ATI. + * Workaround is to not close them at all if driver vendor is ATI + * during operation. + * </p> + * <p> + * With ATI X11 drivers all connections must be closed at JVM shutdown, + * otherwise a SIGSEGV (after JVM safepoint) will be caused. * </p> */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG", true); - /** Value is <code>true</code>, best 'stable' results if always using XInitThreads(). */ - public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; - - /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ - public static final boolean HAS_XLOCKDISPLAY_BUG = true; - - public static final boolean DEBUG = Debug.debug("X11Util"); + /** See {@link #ATI_HAS_XCLOSEDISPLAY_BUG}. */ + public static final boolean HAS_XCLOSEDISPLAY_BUG = Debug.isPropertyDefined("nativewindow.debug.X11Util.HAS_XCLOSEDISPLAY_BUG", true); + + /** + * See Bug 623 - https://jogamp.org/bugzilla/show_bug.cgi?id=623 + */ + public static final boolean ATI_HAS_MULTITHREADING_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG", true); + public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true); public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); private static String nullDisplayName = null; - private static boolean isX11LockAvailable = false; - private static boolean requiresX11Lock = true; private static volatile boolean isInit = false; - private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues + private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues, or GLRendererQuirks.DontCloseX11Display + private static boolean hasThreadingIssues = false; // ATI/AMD X11 driver issues - private static int setX11ErrorHandlerRecCount = 0; - private static Object setX11ErrorHandlerLock = new Object(); + private static final Object setX11ErrorHandlerLock = new Object(); + private static final String X11_EXTENSION_ATIFGLRXDRI = "ATIFGLRXDRI"; + private static final String X11_EXTENSION_ATIFGLEXTENSION = "ATIFGLEXTENSION"; - /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static void initSingleton() { if(!isInit) { @@ -104,59 +116,84 @@ public class X11Util { if(!isInit) { isInit = true; if(DEBUG) { - System.out.println("X11UtilUtil.initSingleton()"); + System.out.println("X11Util.initSingleton()"); } if(!NWJNILibLoader.loadNativeWindow("x11")) { throw new NativeWindowException("NativeWindow X11 native library load error."); } - - final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED ; - final boolean isXInitThreadsOK = initialize0( callXInitThreads, XERROR_STACKDUMP); - isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; - - final long dpy = X11Lib.XOpenDisplay(null); + + final boolean isInitOK = initialize0( XERROR_STACKDUMP ); + + final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION; + final long dpy = X11Lib.XOpenDisplay(PropertyAccess.getProperty("nativewindow.x11.display.default", true)); if(0 != dpy) { if(XSYNC_ENABLED) { X11Lib.XSynchronize(dpy, true); - } + } try { nullDisplayName = X11Lib.XDisplayString(dpy); + hasX11_EXTENSION_ATIFGLRXDRI = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLRXDRI); + hasX11_EXTENSION_ATIFGLEXTENSION = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLEXTENSION); } finally { X11Lib.XCloseDisplay(dpy); } } else { nullDisplayName = "nil"; + hasX11_EXTENSION_ATIFGLRXDRI = false; + hasX11_EXTENSION_ATIFGLEXTENSION = false; + } + final boolean isATIFGLRX = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION ; + hasThreadingIssues = ATI_HAS_MULTITHREADING_BUG && isATIFGLRX; + if ( !markAllDisplaysUnclosable ) { + markAllDisplaysUnclosable = ( ATI_HAS_XCLOSEDISPLAY_BUG && isATIFGLRX ) || HAS_XCLOSEDISPLAY_BUG; } - + if(DEBUG) { - System.err.println("X11Util requiresX11Lock "+requiresX11Lock+ - ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ - ", isX11LockAvailable "+isX11LockAvailable+ - ", X11 Display(NULL) <"+nullDisplayName+">"+ - ", XSynchronize Enabled: "+XSYNC_ENABLED); + System.err.println("X11Util.initSingleton(): OK "+isInitOK+"]"+ + ",\n\t X11 Display(NULL) <"+nullDisplayName+">"+ + ",\n\t XSynchronize Enabled: " + XSYNC_ENABLED+ + ",\n\t X11_EXTENSION_ATIFGLRXDRI " + hasX11_EXTENSION_ATIFGLRXDRI+ + ",\n\t X11_EXTENSION_ATIFGLEXTENSION " + hasX11_EXTENSION_ATIFGLEXTENSION+ + ",\n\t requiresToolkitLock "+requiresToolkitLock()+ + ",\n\t hasThreadingIssues "+hasThreadingIssues()+ + ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable() + ); // Thread.dumpStack(); } } } } } - - /** + + // not exactly thread safe, but good enough for our purpose, + // which is to tag a NamedDisplay uncloseable after creation. + private static Object globalLock = new Object(); + private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name + private static List<NamedDisplay> openDisplayList = new ArrayList<NamedDisplay>(); // open, no close attempt + private static List<NamedDisplay> reusableDisplayList = new ArrayList<NamedDisplay>(); // close attempt, marked uncloseable, for reuse + private static List<NamedDisplay> pendingDisplayList = new ArrayList<NamedDisplay>(); // all open (close attempt or reusable) in creation order + private static final HashMap<String /* displayName */, Boolean> displayXineramaEnabledMap = new HashMap<String, Boolean>(); + + /** * Cleanup resources. * <p> * Called by {@link NativeWindowFactory#shutdown()} * </p> + * @see ToolkitProperties */ public static void shutdown() { if(isInit) { synchronized(X11Util.class) { - if(isInit) { + if(isInit) { final boolean isJVMShuttingDown = NativeWindowFactory.isJVMShuttingDown() ; - if(DEBUG || openDisplayMap.size() > 0 || reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0) { + if( DEBUG || + ( ( openDisplayMap.size() > 0 || reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) && + ( reusableDisplayList.size() != pendingDisplayList.size() || !markAllDisplaysUnclosable ) + ) ) { System.err.println("X11Util.Display: Shutdown (JVM shutdown: "+isJVMShuttingDown+ ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ ", reusable (open, marked uncloseable): "+reusableDisplayList.size()+ - ", pending (post closing): "+pendingDisplayList.size()+ + ", pending (open in creation order): "+pendingDisplayList.size()+ ")"); if(DEBUG) { Thread.dumpStack(); @@ -164,21 +201,24 @@ public class X11Util { if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); } - if( reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) { - X11Util.dumpPendingDisplayConnections(); + if(DEBUG) { + if( reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) { + X11Util.dumpPendingDisplayConnections(); + } } } - - synchronized(globalLock) { - // Only at JVM shutdown time, since AWT impl. seems to - // dislike closing of X11 Display's (w/ ATI driver). - if( isJVMShuttingDown ) { - isInit = false; - closePendingDisplayConnections(); + + // Only at JVM shutdown time, since AWT impl. seems to + // dislike closing of X11 Display's (w/ ATI driver). + if( isJVMShuttingDown ) { + synchronized(globalLock) { + isInit = false; + closePendingDisplayConnections(); openDisplayList.clear(); reusableDisplayList.clear(); pendingDisplayList.clear(); openDisplayMap.clear(); + displayXineramaEnabledMap.clear(); shutdown0(); } } @@ -187,53 +227,52 @@ public class X11Util { } } - public static synchronized boolean isNativeLockAvailable() { - return isX11LockAvailable; + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean requiresToolkitLock() { + return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock per display connection. } - public static synchronized boolean requiresToolkitLock() { - return requiresX11Lock; + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { + return hasThreadingIssues; // JOGL impl. may utilize special locking "somewhere" } - public static void setX11ErrorHandler(boolean onoff, boolean quiet) { + public static void setX11ErrorHandler(final boolean onoff, final boolean quiet) { synchronized(setX11ErrorHandlerLock) { - if(onoff) { - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(true, quiet); - } - setX11ErrorHandlerRecCount++; - } else { - if(0 >= setX11ErrorHandlerRecCount) { - throw new InternalError(); - } - setX11ErrorHandlerRecCount--; - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(false, false); - } - } + setX11ErrorHandler0(onoff, quiet); } } public static String getNullDisplayName() { return nullDisplayName; } - + + public static void markAllDisplaysUnclosable() { + synchronized(globalLock) { + markAllDisplaysUnclosable = true; + for(int i=0; i<openDisplayList.size(); i++) { + openDisplayList.get(i).setUncloseable(true); + } + for(int i=0; i<reusableDisplayList.size(); i++) { + reusableDisplayList.get(i).setUncloseable(true); + } + for(int i=0; i<pendingDisplayList.size(); i++) { + pendingDisplayList.get(i).setUncloseable(true); + } + } + } + public static boolean getMarkAllDisplaysUnclosable() { return markAllDisplaysUnclosable; } - public static void setMarkAllDisplaysUnclosable(boolean v) { - markAllDisplaysUnclosable = v; - } - - private X11Util() {} - // not exactly thread safe, but good enough for our purpose, - // which is to tag a NamedDisplay uncloseable after creation. - private static Object globalLock = new Object(); - private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name - private static List<NamedDisplay> openDisplayList = new ArrayList<NamedDisplay>(); - private static List<NamedDisplay> reusableDisplayList = new ArrayList<NamedDisplay>(); - private static List<NamedDisplay> pendingDisplayList = new ArrayList<NamedDisplay>(); + private X11Util() {} public static class NamedDisplay { final String name; @@ -243,7 +282,7 @@ public class X11Util { boolean unCloseable; Throwable creationStack; - protected NamedDisplay(String name, long handle) { + protected NamedDisplay(final String name, final long handle) { this.name=name; this.handle=handle; this.refCount=0; @@ -261,58 +300,58 @@ public class X11Util { } } + @Override public final int hashCode() { return hash32; } - - public final boolean equals(Object obj) { + + @Override + public final boolean equals(final Object obj) { if(this == obj) { return true; } if(obj instanceof NamedDisplay) { return handle == ((NamedDisplay) obj).handle; } return false; } - + public final void addRef() { refCount++; } public final void removeRef() { refCount--; } - + public final String getName() { return name; } public final long getHandle() { return handle; } public final int getRefCount() { return refCount; } - public final void setUncloseable(boolean v) { unCloseable = v; } + public final void setUncloseable(final boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } public final Throwable getCreationStack() { return creationStack; } @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override public String toString() { return "NamedX11Display["+name+", 0x"+Long.toHexString(handle)+", refCount "+refCount+", unCloseable "+unCloseable+"]"; } } /** - * Closing pending Display connections in reverse order. + * Closing pending Display connections in original creation order, if {@link #getMarkAllDisplaysUnclosable()} is true. * * @return number of closed Display connections */ - public static int closePendingDisplayConnections() { + private static int closePendingDisplayConnections() { int num=0; synchronized(globalLock) { - if(DEBUG) { - System.err.println("X11Util: Closing Pending X11 Display Connections in order of their creation: "+pendingDisplayList.size()); - } - for(int i=0; i<pendingDisplayList.size(); i++) { - NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); + if( getMarkAllDisplaysUnclosable() ) { + for(int i=0; i<pendingDisplayList.size(); i++) { + final NamedDisplay ndpy = pendingDisplayList.get(i); + if(DEBUG) { + final boolean closeAttempted = !openDisplayMap.containsKey(ndpy.getHandle()); + System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy+" - closeAttempted "+closeAttempted); + } + XCloseDisplay(ndpy.getHandle()); + num++; + } if(DEBUG) { - System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy); + System.err.println("X11Util.closePendingDisplayConnections(): Closed "+num+" pending display connections"); } - XCloseDisplay(ndpy.getHandle()); - num++; } } return num; @@ -323,15 +362,15 @@ public class X11Util { return openDisplayList.size(); } } - + public static void dumpOpenDisplayConnections() { synchronized(globalLock) { System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size()); for(int i=0; i<openDisplayList.size(); i++) { - NamedDisplay ndpy = openDisplayList.get(i); + final NamedDisplay ndpy = openDisplayList.get(i); System.err.println("X11Util: Open["+i+"]: "+ndpy); if(null!=ndpy) { - Throwable t = ndpy.getCreationStack(); + final Throwable t = ndpy.getCreationStack(); if(null!=t) { t.printStackTrace(); } @@ -339,7 +378,7 @@ public class X11Util { } } } - + public static int getReusableDisplayConnectionNumber() { synchronized(globalLock) { return reusableDisplayList.size(); @@ -356,10 +395,10 @@ public class X11Util { synchronized(globalLock) { System.err.println("X11Util: Reusable X11 Display Connections: "+reusableDisplayList.size()); for(int i=0; i<reusableDisplayList.size(); i++) { - NamedDisplay ndpy = (NamedDisplay) reusableDisplayList.get(i); + final NamedDisplay ndpy = reusableDisplayList.get(i); System.err.println("X11Util: Reusable["+i+"]: "+ndpy); if(null!=ndpy) { - Throwable t = ndpy.getCreationStack(); + final Throwable t = ndpy.getCreationStack(); if(null!=t) { t.printStackTrace(); } @@ -367,10 +406,10 @@ public class X11Util { } System.err.println("X11Util: Pending X11 Display Connections (creation order): "+pendingDisplayList.size()); for(int i=0; i<pendingDisplayList.size(); i++) { - NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); + final NamedDisplay ndpy = pendingDisplayList.get(i); System.err.println("X11Util: Pending["+i+"]: "+ndpy); if(null!=ndpy) { - Throwable t = ndpy.getCreationStack(); + final Throwable t = ndpy.getCreationStack(); if(null!=t) { t.printStackTrace(); } @@ -379,7 +418,7 @@ public class X11Util { } } - public static boolean markDisplayUncloseable(long handle) { + public static boolean markDisplayUncloseable(final long handle) { NamedDisplay ndpy; synchronized(globalLock) { ndpy = (NamedDisplay) openDisplayMap.get(handle); @@ -397,8 +436,8 @@ public class X11Util { NamedDisplay namedDpy = null; name = validateDisplayName(name); boolean reused = false; - - synchronized(globalLock) { + + synchronized(globalLock) { for(int i=0; i<reusableDisplayList.size(); i++) { if(reusableDisplayList.get(i).getName().equals(name)) { namedDpy = reusableDisplayList.remove(i); @@ -431,11 +470,9 @@ public class X11Util { return namedDpy.getHandle(); } - public static void closeDisplay(long handle) { - NamedDisplay namedDpy; - + public static void closeDisplay(final long handle) { synchronized(globalLock) { - namedDpy = (NamedDisplay) openDisplayMap.remove(handle); + final NamedDisplay namedDpy = (NamedDisplay) openDisplayMap.remove(handle); if(null==namedDpy) { X11Util.dumpPendingDisplayConnections(); throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped. Thread "+Thread.currentThread().getName()); @@ -444,38 +481,43 @@ public class X11Util { X11Util.dumpPendingDisplayConnections(); throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") Mapping error: "+namedDpy+". Thread "+Thread.currentThread().getName()); } - + namedDpy.removeRef(); if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } - - if(!namedDpy.isUncloseable()) { + + if( markAllDisplaysUnclosable ) { + // if set-mark 'slipped' this one .. just to be safe! + namedDpy.setUncloseable(true); + } + if( !namedDpy.isUncloseable() ) { XCloseDisplay(namedDpy.getHandle()); pendingDisplayList.remove(namedDpy); } else { // for reuse + X11Lib.XSync(namedDpy.getHandle(), true); // flush output buffer and discard all events reusableDisplayList.add(namedDpy); } - + if(DEBUG) { System.err.println("X11Util.Display: Closed (real: "+(!namedDpy.isUncloseable())+") "+namedDpy+". Thread "+Thread.currentThread().getName()); - } + } } } - public static NamedDisplay getNamedDisplay(long handle) { + public static NamedDisplay getNamedDisplay(final long handle) { synchronized(globalLock) { return (NamedDisplay) openDisplayMap.get(handle); } } - /** + /** * @return If name is null, it returns the previous queried NULL display name, * otherwise the name. */ - public static String validateDisplayName(String name) { + public static String validateDisplayName(final String name) { return ( null == name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) ? getNullDisplayName() : name ; } - public static String validateDisplayName(String name, long handle) { + public static String validateDisplayName(String name, final long handle) { if( ( null==name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) && 0!=handle) { name = X11Lib.XDisplayString(handle); } @@ -488,54 +530,61 @@ public class X11Util { ** *******************************/ - public static long XOpenDisplay(String arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - long handle = X11Lib.XOpenDisplay(arg0); - if(XSYNC_ENABLED && 0 != handle) { - X11Lib.XSynchronize(handle, true); - } - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - // Thread.dumpStack(); - } - return handle; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + public static long XOpenDisplay(final String arg0) { + final long handle = X11Lib.XOpenDisplay(arg0); + if(XSYNC_ENABLED && 0 != handle) { + X11Lib.XSynchronize(handle, true); } + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); + } + return handle; } - public static int XCloseDisplay(long display) { - NativeWindowFactory.getDefaultToolkitLock().lock(); + public static int XCloseDisplay(final long display) { + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); + } + int res = -1; try { - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - // Thread.dumpStack(); - } - int res = -1; - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - res = X11Lib.XCloseDisplay(display); - } catch (Exception ex) { - System.err.println("X11Util: Catched Exception:"); - ex.printStackTrace(); - } finally { - X11Util.setX11ErrorHandler(false, false); - } - return res; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + res = X11Lib.XCloseDisplay(display); + } catch (final Exception ex) { + System.err.println("X11Util: Caught exception:"); + ex.printStackTrace(); } + return res; } static volatile boolean XineramaFetched = false; static long XineramaLibHandle = 0; static long XineramaQueryFunc = 0; - - public static boolean XineramaIsEnabled(long display) { - if(0==display) { - throw new IllegalArgumentException("Display NULL"); + + public static boolean XineramaIsEnabled(final X11GraphicsDevice device) { + if(null == device) { + throw new IllegalArgumentException("X11 Display device is NULL"); } + device.lock(); + try { + return XineramaIsEnabled(device.getHandle()); + } finally { + device.unlock(); + } + } + + public static boolean XineramaIsEnabled(final long displayHandle) { + if( 0 == displayHandle ) { + throw new IllegalArgumentException("X11 Display handle is NULL"); + } + final String displayName = X11Lib.XDisplayString(displayHandle); + synchronized(displayXineramaEnabledMap) { + final Boolean b = displayXineramaEnabledMap.get(displayName); + if(null != b) { + return b.booleanValue(); + } + } + final boolean res; if(!XineramaFetched) { // volatile: ok synchronized(X11Util.class) { if( !XineramaFetched ) { @@ -548,22 +597,27 @@ public class X11Util { } } if(0!=XineramaQueryFunc) { - final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, display); + res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, displayHandle); + } else { if(DEBUG) { - System.err.println("XineramaIsEnabled: "+res); + System.err.println("XineramaIsEnabled: Couldn't bind to Xinerama - lib 0x"+Long.toHexString(XineramaLibHandle)+ + "query 0x"+Long.toHexString(XineramaQueryFunc)); } - return res; - } else if(DEBUG) { - System.err.println("XineramaIsEnabled: Couldn't bind to Xinerama - lib 0x"+Long.toHexString(XineramaLibHandle)+ - "query 0x"+Long.toHexString(XineramaQueryFunc)); + res = false; } - return false; + synchronized(displayXineramaEnabledMap) { + if(DEBUG) { + System.err.println("XineramaIsEnabled Cache: Display "+displayName+" (0x"+Long.toHexString(displayHandle)+") -> "+res); + } + displayXineramaEnabledMap.put(displayName, Boolean.valueOf(res)); + } + return res; } - + private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI - - private static native boolean initialize0(boolean firstUIActionOnProcess, boolean debug); + + private static native boolean initialize0(boolean debug); private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java index 1de03e8be..6b606df97 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.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 @@ -59,16 +59,17 @@ import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory { - + public static void registerFactory() { GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, CapabilitiesImmutable.class, new X11AWTGraphicsConfigurationFactory()); - } + } private X11AWTGraphicsConfigurationFactory() { } + @Override protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, final int nativeVisualID) { if (absScreen != null && !(absScreen instanceof AWTGraphicsScreen)) { throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects"); @@ -79,19 +80,19 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen, nativeVisualID); } - + public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen, int nativeVisualID) { + CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, final AWTGraphicsScreen awtScreen, final int nativeVisualID) { if(DEBUG) { System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen); } - + final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); - + final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); final long displayHandle; - boolean owner = false; + final boolean owner; if(0==displayHandleAWT) { displayHandle = X11Util.openDisplay(null); owner = true; @@ -101,8 +102,8 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac } else { /** * Using the AWT display handle works fine with NVidia. - * However we experienced different results w/ AMD drivers, - * some work, but some behave erratic. + * However we experienced different results w/ AMD drivers, + * some work, but some behave erratic. * I.e. hangs in XQueryExtension(..) via X11GraphicsScreen. */ final String displayName = X11Lib.XDisplayString(displayHandleAWT); @@ -112,15 +113,14 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println(getThreadName()+" - X11AWTGraphicsConfigurationFactory: AWT dpy "+displayName+" / "+toHexString(displayHandleAWT)+", create X11 display "+toHexString(displayHandle)); } } - final ToolkitLock lock = owner ? - NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock - NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle); - final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); + // Global JAWT lock required - No X11 resource locking due to private display connection + final ToolkitLock lock = NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT); + final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); if(DEBUG) { System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen); } - + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device, capsChosen); AbstractGraphicsConfiguration aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen, nativeVisualID); if (aConfig == null) { @@ -130,7 +130,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println("X11AWTGraphicsConfigurationFactory: chosen config: "+aConfig); // Thread.dumpStack(); } - + // // Match the X11/GL Visual with AWT: // - choose a config AWT agnostic and then @@ -138,12 +138,12 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac // // The resulting GraphicsConfiguration has to be 'forced' on the AWT native peer, // ie. returned by GLCanvas's getGraphicsConfiguration() befor call by super.addNotify(). - // + // final GraphicsConfiguration[] configs = device.getConfigurations(); int visualID = aConfig.getVisualID(VIDType.NATIVE); if(VisualIDHolder.VID_UNDEFINED != visualID) { for (int i = 0; i < configs.length; i++) { - GraphicsConfiguration gc = configs[i]; + final GraphicsConfiguration gc = configs[i]; if (gc != null) { if (X11SunJDKReflection.graphicsConfigurationGetVisualID(gc) == visualID) { if(DEBUG) { diff --git a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c index 2a6651007..5c77b6d46 100644 --- a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c +++ b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c @@ -43,7 +43,7 @@ #define PLATFORM_DSI_SIZE sizeof(JAWT_Win32DrawingSurfaceInfo) #elif defined(linux) || defined(__sun) || defined(__FreeBSD__) || defined(_HPUX) #define PLATFORM_DSI_SIZE sizeof(JAWT_X11DrawingSurfaceInfo) -#elif defined(macosx) +#elif defined(__APPLE__) #define PLATFORM_DSI_SIZE sizeof(JAWT_MacOSXDrawingSurfaceInfo) #else ERROR: port JAWT_DrawingSurfaceInfo.c to your platform diff --git a/src/nativewindow/native/NativewindowCommon.c b/src/nativewindow/native/NativewindowCommon.c index d2fdd5d69..e65f87272 100644 --- a/src/nativewindow/native/NativewindowCommon.c +++ b/src/nativewindow/native/NativewindowCommon.c @@ -1,21 +1,57 @@ #include "NativewindowCommon.h" #include <string.h> +#include <sys/time.h> + +// #define STDERR_TO_FILE 1 static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; +static JavaVM *_jvmHandle = NULL; +static int _jvmVersion = 0; + +int NativewindowCommon_init(JNIEnv *env) { + if(NULL==_jvmHandle) { + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't use %s", ClazzNameRuntimeException); + } + #ifdef STDERR_TO_FILE + FILE * old_stderr = stderr; + FILE * new_stderr = freopen("jogamp_stderr.log", "w", stderr); + fprintf(stderr, "STDERR_TO_FILE: %p -> %p\n", old_stderr, new_stderr); + #endif + return 1; + } + return 0; +} + void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); - fprintf(stderr, "%s\n", buffer); - (*env)->FatalError(env, buffer); + fprintf(stderr, "%s\n", buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + } + } } void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) @@ -23,27 +59,20 @@ void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, . char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if(NULL==_jvmHandle) { + NativewindowCommon_FatalError(env, "Nativewindow: NULL JVM handle, call NativewindowCommon_init 1st\n"); + return; + } - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); -int NativewindowCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { - jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); - if(NULL==c) { - NativewindowCommon_FatalError(env, "Nativewindow: can't find %s", ClazzNameRuntimeException); - } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==runtimeExceptionClz) { - NativewindowCommon_FatalError(env, "Nativewindow: can't use %s", ClazzNameRuntimeException); + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); } - return 1; } - return 0; } const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText) { @@ -67,37 +96,63 @@ const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass cla jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; - strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); - if (strChars != NULL) { - (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + if( NULL != env && 0 != str ) { + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } } return strChars; } -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached) { +JNIEnv* NativewindowCommon_GetJNIEnv (int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; + if(NULL==_jvmHandle) { + fprintf(stderr, "Nativewindow GetJNIEnv: NULL JVM handle, call NativewindowCommon_init 1st\n"); + return NULL; + } + // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; + envRes = (*_jvmHandle)->GetEnv(_jvmHandle, (void **) &curEnv, _jvmVersion) ; if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); + if( asDaemon ) { + envRes = (*_jvmHandle)->AttachCurrentThreadAsDaemon(_jvmHandle, (void**) &newEnv, NULL); + } else { + envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL); + } + if( JNI_OK != envRes ) { + fprintf(stderr, "Nativewindow GetJNIEnv: Can't attach thread: %d\n", envRes); return NULL; } curEnv = newEnv; } else if( JNI_OK != envRes ) { // oops .. - fprintf(stderr, "can't GetEnv: %d\n", envRes); + fprintf(stderr, "Nativewindow GetJNIEnv: Can't GetEnv: %d\n", envRes); return NULL; } if (curEnv==NULL) { - fprintf(stderr, "env is NULL\n"); + fprintf(stderr, "Nativewindow GetJNIEnv: env is NULL\n"); return NULL; } *shallBeDetached = NULL != newEnv; return curEnv; } +void NativewindowCommon_ReleaseJNIEnv (int shallBeDetached) { + if(NULL == _jvmHandle) { + fprintf(stderr, "Nativewindow ReleaseJNIEnv: No JavaVM handle registered, call NativewindowCommon_init(..) 1st"); + } else if(shallBeDetached) { + (*_jvmHandle)->DetachCurrentThread(_jvmHandle); + } +} + +int64_t NativewindowCommon_CurrentTimeMillis() { + struct timeval tv; + gettimeofday(&tv,NULL); + return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + diff --git a/src/nativewindow/native/NativewindowCommon.h b/src/nativewindow/native/NativewindowCommon.h index 73b890c4f..f19552e33 100644 --- a/src/nativewindow/native/NativewindowCommon.h +++ b/src/nativewindow/native/NativewindowCommon.h @@ -1,9 +1,37 @@ +/** + * Copyright 2011 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. + */ #ifndef NATIVEWINDOW_COMMON_H #define NATIVEWINDOW_COMMON_H 1 #include <jni.h> #include <stdlib.h> +#include <gluegen_stdint.h> int NativewindowCommon_init(JNIEnv *env); @@ -13,6 +41,40 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...); void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached); +/** + * + * 1) Init static jvmHandle, jvmVersion and clazz references + * from an early initialization call w/ valid 'JNIEnv * env' + + NativewindowCommon_init(env); + + * + * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv + * + + int asDaemon = 0; + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(asDaemon, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("drawRect: null JNIEnv\n"); + return; + } + + * + * 3) Use JNIEnv .. + * + .. your JNIEnv code here .. + + * + * 4) Detach thread from JVM if required, i.e. not attached as daemon! + * Not recommended for recurring _daemon_ threads (performance) + * + NewtCommon_ReleaseJNIEnv(shallBeDetached); + */ +JNIEnv* NativewindowCommon_GetJNIEnv (int asDaemon, int * shallBeDetached); + +void NativewindowCommon_ReleaseJNIEnv (int shallBeDetached); + +int64_t NativewindowCommon_CurrentTimeMillis(); #endif diff --git a/src/nativewindow/native/macosx/NativeWindowProtocols.h b/src/nativewindow/native/macosx/NativeWindowProtocols.h new file mode 100644 index 000000000..98e864f8b --- /dev/null +++ b/src/nativewindow/native/macosx/NativeWindowProtocols.h @@ -0,0 +1,58 @@ +/** + * 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. + */ + +#ifndef NATIVEWINDOWPROTOCOLS_H +#define NATIVEWINDOWPROTOCOLS_H 1 + +/** + * CALayer size needs to be set using the AWT component size. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_SIZE ( 1 << 0 ) + +/** + * CALayer position needs to be set to zero. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_POSITION ( 1 << 1 ) + +/** + * CALayer position needs to be derived from AWT position. + * in relation to super CALayer. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_LAYOUT ( 1 << 2 ) + +#import <Foundation/NSGeometry.h> + +@protocol NWDedicatedFrame +- (void)setDedicatedFrame:(CGRect)dFrame quirks:(int)quirks; +@end + +#endif /* NATIVEWINDOWPROTOCOLS_H_ */ + diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 1cf41fc9d..127b329d1 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -32,13 +32,14 @@ #include <stdarg.h> #include <unistd.h> #include <AppKit/AppKit.h> +#import <QuartzCore/QuartzCore.h> +#import "NativeWindowProtocols.h" #include "NativewindowCommon.h" #include "jogamp_nativewindow_macosx_OSXUtil.h" #include "jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow.h" #include <jawt_md.h> -#import <JavaNativeFoundation.h> // #define VERBOSE 1 // @@ -49,6 +50,16 @@ #define DBG_PRINT(...) #endif +// #define VERBOSE2 1 +// +#ifdef VERBOSE2 + #define DBG_PRINT2(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT2(...) +#endif + +// #define DBG_LIFECYCLE 1 + static const char * const ClazzNameRunnable = "java/lang/Runnable"; static jmethodID runnableRunID = NULL; @@ -64,11 +75,9 @@ static const char * const ClazzNameInsetsCstrSignature = "(IIII)V"; static jclass insetsClz = NULL; static jmethodID insetsCstr = NULL; -static int _initialized=0; - JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { - if(0==_initialized) { + if( NativewindowCommon_init(env) ) { jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -108,7 +117,6 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { if(NULL==runnableRunID) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); } - _initialized=1; } return JNI_TRUE; } @@ -116,13 +124,25 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_isNSView0(JNIEnv *env, jclass _unused, jlong object) { NSObject *nsObj = (NSObject*) (intptr_t) object; - return [nsObj isMemberOfClass:[NSView class]]; + jboolean u = [nsObj isKindOfClass:[NSView class]]; + DBG_PRINT( "isNSView(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; } JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_isNSWindow0(JNIEnv *env, jclass _unused, jlong object) { NSObject *nsObj = (NSObject*) (intptr_t) object; - return [nsObj isMemberOfClass:[NSWindow class]]; + jboolean u = [nsObj isKindOfClass:[NSWindow class]]; + DBG_PRINT( "isNSWindow(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +static CGDirectDisplayID OSXUtil_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { + // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! + NSDictionary * dict = [screen deviceDescription]; + NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; + // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size + return (CGDirectDisplayID) [val integerValue]; } /* @@ -139,10 +159,6 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS * return location in 0/0 top-left space, * OSX is 0/0 bottom-left space naturally */ - NSRect r; - int dest_x=-1; - int dest_y=-1; - NSObject *nsObj = (NSObject*) (intptr_t) winOrView; NSWindow* win = NULL; NSView* view = NULL; @@ -154,27 +170,36 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS view = (NSView*) nsObj; win = [view window]; } else { - NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj); + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); } - NSScreen* screen = [win screen]; - NSRect screenRect = [screen frame]; - NSRect winFrame = [win frame]; + NSRect viewFrame = [view frame]; + NSRect r; r.origin.x = src_x; - r.origin.y = winFrame.size.height - src_y; // y-flip for 0/0 top-left + r.origin.y = viewFrame.size.height - src_y; // y-flip for 0/0 top-left r.size.width = 0; r.size.height = 0; // NSRect rS = [win convertRectToScreen: r]; // 10.7 - NSPoint oS = [win convertBaseToScreen: r.origin]; - /** - NSLog(@"LOS.1: (bottom-left) %d/%d, screen-y[0: %d, h: %d], (top-left) %d/%d\n", - (int)oS.x, (int)oS.y, (int)screenRect.origin.y, (int) screenRect.size.height, - (int)oS.x, (int)(screenRect.origin.y + screenRect.size.height - oS.y)); */ + NSPoint oS = [win convertBaseToScreen: r.origin]; // BL-screen - dest_x = (int) oS.x; - dest_y = (int) screenRect.origin.y + screenRect.size.height - oS.y; + NSScreen* screen = [win screen]; + CGDirectDisplayID display = OSXUtil_getCGDirectDisplayIDByNSScreen(screen); + CGRect frameTL = CGDisplayBounds (display); // origin top-left + NSRect frameBL = [screen frame]; // origin bottom-left + oS.y = frameTL.origin.y + frameTL.size.height - ( oS.y - frameBL.origin.y ); // y-flip from BL-screen -> TL-screen - jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y); +#ifdef VERBOSE + NSRect winFrame = [win frame]; + DBG_PRINT( "GetLocationOnScreen0(window: %p):: point-in[%d/%d], winFrame[%d/%d %dx%d], viewFrame[%d/%d %dx%d], screen tl[%d/%d %dx%d] bl[%d/%d %dx%d] -> %d/%d\n", + win, (int)src_x, (int)src_y, + (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height, + (int)viewFrame.origin.x, (int)viewFrame.origin.y, (int)viewFrame.size.width, (int)viewFrame.size.height, + (int)frameTL.origin.x, (int)frameTL.origin.y, (int)frameTL.size.width, (int)frameTL.size.height, + (int)frameBL.origin.x, (int)frameBL.origin.y, (int)frameBL.size.width, (int)frameBL.size.height, + (int)oS.x, (int)oS.y); +#endif + + jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)oS.x, (jint)oS.y); [pool release]; @@ -203,7 +228,7 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0 view = (NSView*) nsObj; win = [view window]; } else { - NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj); + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); } NSRect frameRect = [win frame]; @@ -226,6 +251,75 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetPixelScale0 + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetPixelScale0 + (JNIEnv *env, jclass unused, jint screen_idx) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + CGFloat pixelScale; + NSScreen *screen; + NSArray *screens = [NSScreen screens]; + if( screen_idx<0 || screen_idx>=[screens count] ) { + screen = NULL; + pixelScale = 0.0; + } else { + screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + } + [pool release]; + + return (jdouble)pixelScale; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetPixelScale1 + * Signature: (J)D + */ +JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetPixelScale1 + (JNIEnv *env, jclass unused, jlong winOrView) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; + NSWindow* win = NULL; + NSView* view = NULL; + NSScreen *screen = NULL; + + if( [nsObj isKindOfClass:[NSWindow class]] ) { + win = (NSWindow*) nsObj; + view = [win contentView]; + screen = [win screen]; + } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) { + view = (NSView*) nsObj; + win = [view window]; + screen = [win screen]; + } else { + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); + } + + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + + [pool release]; + + return (jdouble)pixelScale; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: CreateNSWindow0 * Signature: (IIIIZ)J */ @@ -239,7 +333,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0 NSWindow* myWindow = [[NSWindow alloc] initWithContentRect: rect styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered - defer: YES]; + defer: NO]; // Bug 1087: Set default framebuffer, hence enforce NSView realization [myWindow setReleasedWhenClosed: YES]; // default [myWindow setPreservesContentDuringLiveResize: YES]; // Remove animations @@ -255,6 +349,13 @@ NS_ENDHANDLER [myWindow setOpaque: NO]; [myWindow setBackgroundColor: [NSColor clearColor]]; + // Bug 1087: Set default framebuffer, hence enforce NSView realization + // However, using the NSWindow ctor w/ 'defer: NO' seems sufficient + // and we are invisible - no focus! + // NSView* myView = [myWindow contentView]; + // [myView lockFocus]; + // [myView unlockFocus]; + [pool release]; return (jlong) ((intptr_t) myWindow); @@ -313,38 +414,260 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSWindow0 return res; } +/** + * Track lifecycle via DBG_PRINT messages, if VERBOSE is enabled! + */ +@interface MyCALayer: CALayer +{ +@private + BOOL fixedFrameSet; + CGRect fixedFrame; + float visibleOpacity; + BOOL visibleOpacityZeroed; +} +- (id)init; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif +- (id<CAAction>)actionForKey:(NSString *)key ; +- (void)layoutSublayers; +- (void)setFrame:(CGRect) frame; +- (void)fixCALayerLayout: (CALayer*) subLayer visible:(BOOL)visible x:(jint)x y:(jint)y width:(jint)width height:(jint)height caLayerQuirks:(jint)caLayerQuirks force:(jboolean) force; + +@end + +@implementation MyCALayer + +- (id)init +{ + DBG_PRINT("MyCALayer::init.0\n"); + MyCALayer * o = [super init]; + o->fixedFrameSet = 0; + o->fixedFrame = CGRectMake(0, 0, 0, 0); + o->visibleOpacity = 1.0; + o->visibleOpacityZeroed = 0; + DBG_PRINT("MyCALayer::init.X: new %p\n", o); + return o; +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyCALayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyCALayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyCALayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::release: %@",[NSThread callStackSymbols]); + [super release]; + // DBG_PRINT("MyCALayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +- (void)dealloc +{ + DBG_PRINT("MyCALayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::dealloc: %@",[NSThread callStackSymbols]); + [super dealloc]; + // DBG_PRINT("MyCALayer.dealloc.X: %p\n", self); +} + +#endif + +- (id<CAAction>)actionForKey:(NSString *)key +{ + DBG_PRINT("MyCALayer::actionForKey.0 %p key %s -> NIL\n", self, [key UTF8String]); + return nil; + // return [super actionForKey: key]; +} + +- (void)layoutSublayers +{ + if( fixedFrameSet ) { + NSArray* subs = [self sublayers]; + if( NULL != subs ) { + CGRect rFrame = [self frame]; + if( !CGRectEqualToRect(fixedFrame, rFrame) ) { + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.0: Root %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + self, + rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height, + fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height); + #endif + [super setFrame: fixedFrame]; + } + NSUInteger i = 0; + for(i=0; i<[subs count]; i++) { + CALayer* sub = [subs objectAtIndex: i]; + CGRect sFrame = [sub frame]; + CGRect sFrame2 = CGRectMake(0, 0, fixedFrame.size.width, fixedFrame.size.height); + if( !CGRectEqualToRect(sFrame2, sFrame) ) { + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.1: Sub[%d] %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + (int)i, sub, + sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height, + sFrame2.origin.x, sFrame2.origin.y, sFrame2.size.width, sFrame2.size.height); + #endif + [sub setFrame: sFrame2]; + } + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.X: Root %p . Sub[%d] %p : frame r: %lf/%lf %lfx%lf . s: %lf/%lf %lfx%lf\n", + self, (int)i, sub, + rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height, + sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height); + #endif + } + } + } else { + [super layoutSublayers]; + } +} + +- (void) setFrame:(CGRect) frame +{ + if( fixedFrameSet ) { + [super setFrame: fixedFrame]; + } else { + [super setFrame: frame]; + } +} + +- (void)fixCALayerLayout: (CALayer*) subLayer visible:(BOOL)visible x:(jint)x y:(jint)y width:(jint)width height:(jint)height caLayerQuirks:(jint)caLayerQuirks force:(jboolean) force +{ + int loutQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_LAYOUT & caLayerQuirks ); + { + CALayer* superLayer = [self superlayer]; + CGRect superFrame = [superLayer frame]; + CGRect lFrame = [self frame]; + if( visible ) { + // Opacity must be 0 to see through the disabled CALayer + [subLayer setOpacity: visibleOpacity]; + [self setOpacity: visibleOpacity]; + [self setHidden: NO]; + [subLayer setHidden: NO]; + visibleOpacityZeroed = 0; + } else { + [subLayer setHidden: YES]; + [self setHidden: YES]; + if( !visibleOpacityZeroed ) { + visibleOpacity = [self opacity]; + } + [subLayer setOpacity: 0.0]; + [self setOpacity: 0.0]; + visibleOpacityZeroed = 1; + } + int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 ); + int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height ); + if( !posQuirk || loutQuirk ) { + // Use root layer position, sub-layer will be on 0/0, + // Given AWT position is location on screen w/o insets and top/left origin! + fixedFrame.origin.x = x; + fixedFrame.origin.y = superFrame.size.height - height - y; // AWT's position top/left -> bottom/left + posQuirk |= 8; + } else { + // Buggy super layer position, always use 0/0 + fixedFrame.origin.x = 0; + fixedFrame.origin.y = 0; + } + if( !sizeQuirk ) { + fixedFrame.size.width = lFrame.size.width; + fixedFrame.size.height = lFrame.size.height; + } else { + fixedFrame.size.width = width; + fixedFrame.size.height = height; + } + DBG_PRINT("CALayer::FixCALayerLayout0.0: Visible %d, Quirks [%d, pos %d, size %d, lout %d, force %d], Super %p frame %lf/%lf %lfx%lf, Root %p frame %lf/%lf %lfx%lf, usr %d/%d %dx%d -> %lf/%lf %lfx%lf\n", + (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force, + superLayer, superFrame.origin.x, superFrame.origin.y, superFrame.size.width, superFrame.size.height, + self, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height, + x, y, width, height, fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height); + if( posQuirk || sizeQuirk || loutQuirk ) { + fixedFrameSet = 1; + [super setFrame: fixedFrame]; + } + } + if( NULL != subLayer ) { + CGRect lFrame = [subLayer frame]; + int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height ); + CGFloat _x, _y, _w, _h; + int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 ); + // Sub rel. to used root layer + _x = 0; + _y = 0; + posQuirk |= 8; + if( !sizeQuirk ) { + _w = lFrame.size.width; + _h = lFrame.size.height; + } else { + _w = width; + _h = height; + } + DBG_PRINT("CALayer::FixCALayerLayout1.0: Visible %d, Quirks [%d, pos %d, size %d, lout %d, force %d], SubL %p frame %lf/%lf %lfx%lf, usr %dx%d -> %lf/%lf %lfx%lf\n", + (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force, + subLayer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height, + width, height, _x, _y, _w, _h); + if( force || posQuirk || sizeQuirk || loutQuirk ) { + lFrame.origin.x = _x; + lFrame.origin.y = _y; + lFrame.size.width = _w; + lFrame.size.height = _h; + if( [subLayer conformsToProtocol:@protocol(NWDedicatedFrame)] ) { + CALayer <NWDedicatedFrame> * subLayerDS = (CALayer <NWDedicatedFrame> *) subLayer; + [subLayerDS setDedicatedFrame: lFrame quirks: caLayerQuirks]; + } else { + [subLayer setFrame: lFrame]; + } + } + } +} + +@end + /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: CreateCALayer0 - * Signature: (IIII)J + * Signature: (IIF)J */ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 - (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) + (JNIEnv *env, jclass unused, jint width, jint height, jfloat contentsScale) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - CALayer* layer = [[CALayer alloc] init]; - DBG_PRINT("CALayer::CreateCALayer.0: %p %d/%d %dx%d (refcnt %d)\n", layer, (int)x, (int)y, (int)width, (int)height, (int)[layer retainCount]); + MyCALayer* layer = [[MyCALayer alloc] init]; + DBG_PRINT("CALayer::CreateCALayer.0: root %p 0/0 %dx%d @ scale %lf (refcnt %d)\n", layer, (int)width, (int)height, (double)contentsScale, (int)[layer retainCount]); // avoid zero size if(0 == width) { width = 32; } if(0 == height) { height = 32; } +NS_DURING + // Available >= 10.7 + [layer setContentsScale: (CGFloat)contentsScale]; +NS_HANDLER +NS_ENDHANDLER + // initial dummy size ! - CGRect lRect = [layer frame]; - lRect.origin.x = x; - lRect.origin.y = y; - lRect.size.width = width; - lRect.size.height = height; - [layer setFrame: lRect]; + CGRect lFrame = [layer frame]; + lFrame.origin.x = 0; + lFrame.origin.y = 0; + lFrame.size.width = width; + lFrame.size.height = height; + [layer setFrame: lFrame]; // no animations for add/remove/swap sublayers etc // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] [layer removeAllAnimations]; + // [layer addAnimation:nil forKey:kCATransition]; [layer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; [layer setNeedsDisplayOnBoundsChange: YES]; - DBG_PRINT("CALayer::CreateCALayer.1: %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); - DBG_PRINT("CALayer::CreateCALayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - + DBG_PRINT("CALayer::CreateCALayer.1: root %p %lf/%lf %lfx%lf\n", layer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height); [pool release]; + DBG_PRINT("CALayer::CreateCALayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); return (jlong) ((intptr_t) layer); } @@ -352,46 +675,114 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: AddCASublayer0 - * Signature: (JJ)V + * Signature: (JJIIIIIF)V */ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 - (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jint x, jint y, jint width, jint height, jfloat contentsScale, jint caLayerQuirks) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [rootLayer retain]; // Pairs w/ RemoveCASublayer + [subLayer retain]; // Pairs w/ RemoveCASublayer + CGRect lRectRoot = [rootLayer frame]; - DBG_PRINT("CALayer::AddCASublayer0.0: Origin %p frame0: %lf/%lf %lfx%lf\n", - rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); - if(lRectRoot.origin.x!=0 || lRectRoot.origin.y!=0) { - lRectRoot.origin.x = 0; - lRectRoot.origin.y = 0; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [rootLayer setFrame: lRectRoot]; - }]; - DBG_PRINT("CALayer::AddCASublayer0.1: Origin %p frame*: %lf/%lf %lfx%lf\n", - rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + + // Available >= 10.7 + DBG_PRINT("CALayer::AddCASublayer0.0: Quirks %d, Root %p (refcnt %d), Sub %p (refcnt %d), frame0: %lf/%lf %lfx%lf scale %lf\n", + caLayerQuirks, rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount], + lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (float)contentsScale); + +NS_DURING + [subLayer setContentsScale: (CGFloat)contentsScale]; +NS_HANDLER +NS_ENDHANDLER + + [subLayer setFrame:lRectRoot]; + [rootLayer addSublayer:subLayer]; + + // no animations for add/remove/swap sublayers etc + // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] + [rootLayer removeAllAnimations]; + // [rootLayer addAnimation:nil forKey:kCATransition]; // JAU + [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [rootLayer setNeedsDisplayOnBoundsChange: YES]; + [subLayer removeAllAnimations]; + // [subLayer addAnimation:nil forKey:kCATransition]; // JAU + [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [subLayer setNeedsDisplayOnBoundsChange: YES]; + + if( 0 != caLayerQuirks ) { + [rootLayer fixCALayerLayout: subLayer visible:1 x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_TRUE]; + } + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::AddCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: FixCALayerLayout0 + * Signature: (JJIII)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_FixCALayerLayout0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jboolean visible, jint x, jint y, jint width, jint height, jint caLayerQuirks) +{ + if( 0 != caLayerQuirks ) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); + if( NULL == rootLayer ) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null"); + } + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [rootLayer fixCALayerLayout: subLayer visible:(BOOL)visible x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_FALSE]; + + [CATransaction commit]; + + [pool release]; } - DBG_PRINT("CALayer::AddCASublayer0.2: %p . %p %lf/%lf %lfx%lf (refcnt %d)\n", - rootLayer, subLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (int)[subLayer retainCount]); - - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - // simple 1:1 layout ! - [subLayer setFrame:lRectRoot]; - [rootLayer addSublayer:subLayer]; - - // no animations for add/remove/swap sublayers etc - // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] - [rootLayer removeAllAnimations]; - [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; - [rootLayer setNeedsDisplayOnBoundsChange: YES]; - [subLayer removeAllAnimations]; - [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; - [subLayer setNeedsDisplayOnBoundsChange: YES]; - }]; - DBG_PRINT("CALayer::AddCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); - JNF_COCOA_EXIT(env); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: SetCALayerPixelScale0 + * Signature: (JJF)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_SetCALayerPixelScale0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jfloat contentsScale) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); + if( NULL == rootLayer ) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null"); + } + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + +NS_DURING + [rootLayer setContentsScale: (CGFloat)contentsScale]; + if( NULL != subLayer ) { + [subLayer setContentsScale: (CGFloat)contentsScale]; + } +NS_HANDLER +NS_ENDHANDLER + + [CATransaction commit]; + + [pool release]; } /* @@ -402,18 +793,27 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); (void)rootLayer; // no warnings - DBG_PRINT("CALayer::RemoveCASublayer0.0: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [subLayer removeFromSuperlayer]; - }]; - DBG_PRINT("CALayer::RemoveCASublayer0.X: %p . %p\n", rootLayer, subLayer); - JNF_COCOA_EXIT(env); + DBG_PRINT("CALayer::RemoveCASublayer0.0: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [subLayer removeFromSuperlayer]; + [subLayer release]; // Pairs w/ AddCASublayer + [rootLayer release]; // Pairs w/ AddCASublayer + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::RemoveCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); } /* @@ -424,93 +824,113 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 (JNIEnv *env, jclass unused, jlong caLayer) { - JNF_COCOA_ENTER(env); - CALayer* layer = (CALayer*) ((intptr_t) caLayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* layer = (MyCALayer*) ((intptr_t) caLayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + DBG_PRINT("CALayer::DestroyCALayer0.0: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); + [layer release]; // Trigger release and dealloc of root CALayer, it's child etc .. + + [CATransaction commit]; - DBG_PRINT("CALayer::DestroyCALayer0.0: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [layer release]; // performs release! - }]; - DBG_PRINT("CALayer::DestroyCALayer0.X: %p\n", layer); - JNF_COCOA_EXIT(env); + [pool release]; + DBG_PRINT("CALayer::DestroyCALayer0.X: root %p\n", layer); } /* * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow - * Method: SetJAWTRootSurfaceLayer0 - * Signature: (JJ)Z + * Method: GetJAWTSurfaceLayersHandle0 + * Signature: (J)J */ -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0 - (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_GetJAWTSurfaceLayersHandle0 + (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer) { - JNF_COCOA_ENTER(env); JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); if (NULL == dsi) { NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); - return JNI_FALSE; + return 0; } - CALayer* layer = (CALayer*) (intptr_t) caLayer; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: %p -> %p (refcnt %d)\n", surfaceLayers.layer, layer, (int)[layer retainCount]); - surfaceLayers.layer = layer; // already incr. retain count - DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - }]; - JNF_COCOA_EXIT(env); - return JNI_TRUE; + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; + return (jlong) ((intptr_t) surfaceLayers); +} + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: SetJAWTRootSurfaceLayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0 + (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; + DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: pre %p -> root %p (refcnt %d)\n", [surfaceLayers layer], layer, (int)[layer retainCount]); + [surfaceLayers setLayer: [layer retain]]; // Pairs w/ Unset + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); } /* * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow * Method: UnsetJAWTRootSurfaceLayer0 - * Signature: (JJ)Z -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0 - (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0 + (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer) { - JNF_COCOA_ENTER(env); - JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); - if (NULL == dsi) { - NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); - return JNI_FALSE; - } - CALayer* layer = (CALayer*) (intptr_t) caLayer; - { - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - if(layer != surfaceLayers.layer) { - NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); - return JNI_FALSE; - } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; + if(layer != [surfaceLayers layer]) { + NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); + return; } - // [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - DBG_PRINT("CALayer::detachJAWTSurfaceLayer: (%p) %p -> NULL\n", layer, surfaceLayers.layer); - surfaceLayers.layer = NULL; - [layer release]; - // }]; - JNF_COCOA_EXIT(env); - return JNI_TRUE; + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); + [layer release]; // Pairs w/ Set + [surfaceLayers setLayer: NULL]; + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); } - */ @interface MainRunnable : NSObject { - JavaVM *jvmHandle; - int jvmVersion; jobject runnableObj; } -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers; +- (id) initWithRunnable: (jobject)runnable; - (void) jRun; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif + + @end @implementation MainRunnable -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers +- (id) initWithRunnable: (jobject)runnable { - jvmHandle = jvm; - jvmVersion = jvmVers; runnableObj = runnable; return [super init]; } @@ -518,59 +938,144 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow - (void) jRun { int shallBeDetached = 0; - JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NativewindowCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env)); if(NULL!=env) { + DBG_PRINT2("MainRunnable.1.0\n"); (*env)->CallVoidMethod(env, runnableObj, runnableRunID); + DBG_PRINT2("MainRunnable.1.1\n"); + (*env)->DeleteGlobalRef(env, runnableObj); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + DBG_PRINT2("MainRunnable.1.3\n"); + // detaching thread not required - daemon + // NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } + DBG_PRINT2("MainRunnable.X\n"); } -@end +#ifdef DBG_LIFECYCLE +- (id)retain +{ + DBG_PRINT2("MainRunnable::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + id o = [super retain]; + DBG_PRINT2("MainRunnable::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} -/* - * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 - * Signature: (ZLjava/lang/Runnable;)V - */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 - (JNIEnv *env, jclass unused, jboolean jwait, jobject runnable) +- (oneway void)release { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT2("MainRunnable::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; + // DBG_PRINT2("MainRunnable::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} - if ( NO == [NSThread isMainThread] ) { - jobject runnableGlob = (*env)->NewGlobalRef(env, runnable); +- (void)dealloc +{ + DBG_PRINT2("MainRunnable::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + [super dealloc]; + // DBG_PRINT2("MainRunnable.dealloc.X: %p\n", self); +} + +#endif + +@end + +static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayInMS) +{ + BOOL isMainThread = [NSThread isMainThread]; + BOOL forkOnMain = onMain && ( NO == isMainThread || 0 < delayInMS ); - BOOL wait = (JNI_TRUE == jwait) ? YES : NO; - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; + DBG_PRINT2( "RunOnThread0: forkOnMain %d [onMain %d, delay %dms, isMainThread %d], NSApp %d, NSApp-isRunning %d\n", + (int)forkOnMain, (int)onMain, (int)delayInMS, (int)isMainThread, (int)(NULL!=NSApp), (int)([NSApp isRunning])); - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + if ( forkOnMain ) { + jobject runnableObj = (*env)->NewGlobalRef(env, runnable); + + DBG_PRINT2( "RunOnThread.1.0\n"); + MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj]; + + if( onMain ) { + [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; } else { - jvmVersion = (*env)->GetVersion(env); + NSTimeInterval delay = (double)delayInMS/1000.0; + [mr performSelector:@selector(jRun) withObject:nil afterDelay:delay]; } + DBG_PRINT2( "RunOnThread.1.1\n"); - MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableGlob jvmHandle: jvmHandle jvmVersion: jvmVersion]; - [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:wait]; [mr release]; + DBG_PRINT2( "RunOnThread.1.2\n"); - (*env)->DeleteGlobalRef(env, runnableGlob); } else { + DBG_PRINT2( "RunOnThread.2\n"); (*env)->CallVoidMethod(env, runnable, runnableRunID); } + DBG_PRINT2( "RunOnThread.X\n"); +} + +static void OSXUtil_KickNSApp() { + NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined + location: NSMakePoint(0,0) + modifierFlags: 0 + timestamp: 0.0 + windowNumber: 0 + context: nil + subtype: 0 + data1: 0 + data2: 0]; + [NSApp postEvent: event atStart: true]; +} +/** + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: RunOnMainThread0 + * Signature: (ZLjava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 + (JNIEnv *env, jclass unused, jboolean kickNSApp, jobject runnable) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, YES, 0); + if( kickNSApp ) { + OSXUtil_KickNSApp(); + } [pool release]; } /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 + * Method: RunLater0 + * Signature: (ZZLjava/lang/Runnable;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunLater0 + (JNIEnv *env, jclass unused, jboolean onMain, jboolean kickNSApp, jobject runnable, jint delay) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, onMain ? YES : NO, delay); + if( kickNSApp ) { + OSXUtil_KickNSApp(); + } + [pool release]; +} + +/** + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: KickNSApp0 * Signature: (V)V */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_KickNSApp0 + (JNIEnv *env, jclass unused) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + OSXUtil_KickNSApp(); + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: IsMainThread0 + * Signature: (V)Z + */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 (JNIEnv *env, jclass unused) { @@ -614,13 +1119,12 @@ JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshR (JNIEnv *env, jclass unused, jint scrn_idx) { int res = 0; - JNF_COCOA_ENTER(env); - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); DBG_PRINT("GetScreenRefreshRate.0: screen %p\n", (void *)screen); if(NULL != screen) { CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); - DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)display); + DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)(intptr_t)display); if(0 != display) { CFDictionaryRef mode = CGDisplayCurrentMode(display); DBG_PRINT("GetScreenRefreshRate.2: mode %p\n", (void *)mode); @@ -633,9 +1137,8 @@ JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshR if(0 == res) { res = 60; // default .. (experienced on OSX 10.6.8) } - DBG_PRINT(stderr, "GetScreenRefreshRate.X: %d\n", res); - // [pool release]; - JNF_COCOA_EXIT(env); + DBG_PRINT("GetScreenRefreshRate.X: %d\n", (int)res); + [pool release]; return res; } diff --git a/src/nativewindow/native/win32/DeviceDriverQuery.txt b/src/nativewindow/native/win32/DeviceDriverQuery.txt new file mode 100644 index 000000000..7401ed83b --- /dev/null +++ b/src/nativewindow/native/win32/DeviceDriverQuery.txt @@ -0,0 +1,41 @@ + + // INCOMPLETE ! + // + // See Bug 706 and Bug 520 + // https://jogamp.org/bugzilla/show_bug.cgi?id=520 + // https://jogamp.org/bugzilla/show_bug.cgi?id=706 + // + // Device Driver SDK + // http://msdn.microsoft.com/en-us/library/ff553567.aspx#ddk_setupdi_device_information_functions_dg + { + /** + System-Defined Device Setup Classes Available to Vendors (GUID) + + Display Adapters + Class = Display + ClassGuid = {4d36e968-e325-11ce-bfc1-08002be10318} + This class includes video adapters. Drivers for this class include display drivers and video miniport drivers. + + /opt-windows/mingw/include/devguid.h GUID_DEVCLASS_DISPLAY + GUID_DEVCLASS_DISPLAY + HDEVINFO SetupDiGetClassDevs( + _In_opt_ const GUID *ClassGuid, + _In_opt_ PCTSTR Enumerator, + _In_opt_ HWND hwndParent, + _In_ DWORD Flags + ); + + */ + const GUID devClassDisplay = GUID_DEVCLASS_DISPLAY; + // http://msdn.microsoft.com/en-us/library/ff551069.aspx + HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_DISPLAY, NULL /* bus */, NULL /* windows */, DIGCF_PRESENT | DIGCF_PROFILE /* flags */); + DWORD MemberIndex = 0; + SP_DEVINFO_DATA DeviceInfoData; + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + while( TRUE == SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, &DeviceInfoData) ) { + SetupDiGetSelectedDevice(); + MemberIndex++; + } + SetupDiDestroyDeviceInfoList(hDevInfo); + } + diff --git a/src/nativewindow/native/win32/GDImisc.c b/src/nativewindow/native/win32/GDImisc.c index 3ab7f9859..76143c426 100644 --- a/src/nativewindow/native/win32/GDImisc.c +++ b/src/nativewindow/native/win32/GDImisc.c @@ -20,8 +20,10 @@ #ifdef VERBOSE_ON #define DBG_PRINT(args...) fprintf(stderr, args); + #define DBG_PRINT_FLUSH(args...) fprintf(stderr, args); fflush(stderr); #else #define DBG_PRINT(args...) + #define DBG_PRINT_FLUSH(args...) #endif static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; @@ -30,6 +32,162 @@ static const char * const ClazzNamePointCstrSignature = "(II)V"; static jclass pointClz = NULL; static jmethodID pointCstr = NULL; +static jmethodID dumpStackID = NULL; + +typedef struct { + HANDLE threadHandle; + DWORD threadId; + volatile BOOL threadReady; + volatile BOOL threadDead; +} DummyThreadContext; + +typedef struct { + HINSTANCE hInstance; + const TCHAR* wndClassName; + const TCHAR* wndName; + jint x; + jint y; + jint width; + jint height; + volatile HWND hWnd; + volatile BOOL threadReady; +} DummyThreadCommand; + +#define TM_OPENWIN WM_APP+1 +#define TM_CLOSEWIN WM_APP+2 +#define TM_STOP WM_APP+3 + +static const char * sTM_OPENWIN = "TM_OPENWIN"; +static const char * sTM_CLOSEWIN = "TM_CLOSEWIN"; +static const char * sTM_STOP = "TM_STOP"; + +/** 3s timeout */ +static const int64_t TIME_OUT = 3000000; + +static jboolean DDT_CheckAlive(JNIEnv *env, const char *msg, DummyThreadContext *ctx) { + if( ctx->threadDead ) { + NativewindowCommon_throwNewRuntimeException(env, "DDT is dead at %s", msg); + return JNI_FALSE; + } else { + DBG_PRINT_FLUSH("*** DDT-Check ALIVE @ %s\n", msg); + return JNI_TRUE; + } +} + +static jboolean DDT_WaitUntilCreated(JNIEnv *env, DummyThreadContext *ctx, BOOL created) { + const int64_t t0 = NativewindowCommon_CurrentTimeMillis(); + int64_t t1 = t0; + if( created ) { + while( !ctx->threadReady && t1-t0 < TIME_OUT ) { + t1 = NativewindowCommon_CurrentTimeMillis(); + } + if( !ctx->threadReady ) { + NativewindowCommon_throwNewRuntimeException(env, "TIMEOUT (%d ms) while waiting for DDT CREATED", (int)(t1-t0)); + return JNI_FALSE; + } + DBG_PRINT_FLUSH("*** DDT-Check CREATED\n"); + } else { + while( !ctx->threadDead && t1-t0 < TIME_OUT ) { + t1 = NativewindowCommon_CurrentTimeMillis(); + } + if( !ctx->threadDead ) { + NativewindowCommon_throwNewRuntimeException(env, "TIMEOUT (%d ms) while waiting for DDT DESTROYED", (int)(t1-t0)); + return JNI_FALSE; + } + DBG_PRINT_FLUSH("*** DDT-Check DEAD\n"); + } + return JNI_TRUE; +} + +static jboolean DDT_WaitUntilReady(JNIEnv *env, const char *msg, DummyThreadCommand *cmd) { + const int64_t t0 = NativewindowCommon_CurrentTimeMillis(); + int64_t t1 = t0; + while( !cmd->threadReady && t1-t0 < TIME_OUT ) { + t1 = NativewindowCommon_CurrentTimeMillis(); + } + if( !cmd->threadReady ) { + NativewindowCommon_throwNewRuntimeException(env, "TIMEOUT (%d ms) while waiting for DDT %s", (int)(t1-t0), msg); + return JNI_FALSE; + } + DBG_PRINT_FLUSH("*** DDT-Check READY @ %s\n", msg); + return JNI_TRUE; +} + +static HWND DummyWindowCreate + (HINSTANCE hInstance, const TCHAR* wndClassName, const TCHAR* wndName, jint x, jint y, jint width, jint height) +{ + DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dwStyle = WS_OVERLAPPEDWINDOW; + HWND hWnd = CreateWindowEx( dwExStyle, + wndClassName, + wndName, + dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + x, y, width, height, + NULL, NULL, hInstance, NULL ); + return hWnd; +} + +static DWORD WINAPI DummyDispatchThreadFunc(LPVOID param) +{ + MSG msg; + BOOL bRet; + BOOL bEOL=FALSE; + DummyThreadContext *threadContext = (DummyThreadContext*)param; + + /* there can not be any messages for us now, as the creator waits for + threadReady before continuing, but we must use this PeekMessage() to + create the thread message queue */ + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + /* now we can safely say: we have a qeue and are ready to receive messages */ + // threadContext->threadId = GetCurrentThreadId(); + threadContext->threadDead = FALSE; + threadContext->threadReady = TRUE; + + while( !bEOL && (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 ) { + if ( -1 == bRet ) { + fprintf(stderr, "DummyDispatchThread (id %d): GetMessage Error %d, werr %d\n", + (int)threadContext->threadId, (int)bRet, (int)GetLastError()); + fflush(stderr); + bEOL = TRUE; + break; // EOL + } else { + switch(msg.message) { + case TM_OPENWIN: { + DummyThreadCommand *tParam = (DummyThreadCommand*)msg.wParam; + DBG_PRINT_FLUSH("*** DDT-Dispatch OPENWIN\n"); + tParam->hWnd = DummyWindowCreate(tParam->hInstance, tParam->wndClassName, tParam->wndName, tParam->x, tParam->y, tParam->width, tParam->height); + tParam->threadReady = TRUE; + } + break; + case TM_CLOSEWIN: { + DummyThreadCommand *tParam = (DummyThreadCommand*)msg.wParam; + DBG_PRINT_FLUSH("*** DDT-Dispatch CLOSEWIN\n"); + DestroyWindow(tParam->hWnd); + tParam->threadReady = TRUE; + } + break; + case TM_STOP: { + DummyThreadCommand *tParam = (DummyThreadCommand*)msg.wParam; + DBG_PRINT_FLUSH("*** DDT-Dispatch STOP -> DEAD\n"); + tParam->threadReady = TRUE; + bEOL = TRUE; + } + break; // EOL + default: + TranslateMessage(&msg); + DispatchMessage(&msg); + break; + } + } + } + /* dead */ + DBG_PRINT_FLUSH("*** DDT-Dispatch DEAD\n"); + threadContext->threadDead = TRUE; + ExitThread(0); + return 0; +} + HINSTANCE GetApplicationHandle() { return GetModuleHandle(NULL); @@ -37,16 +195,54 @@ HINSTANCE GetApplicationHandle() { /* Java->C glue code: * Java package: jogamp.nativewindow.windows.GDIUtil - * Java method: boolean CreateWindowClass(long hInstance, java.lang.String clazzName, long wndProc) - * C function: BOOL CreateWindowClass(HANDLE hInstance, LPCSTR clazzName, HANDLE wndProc); + * Java method: long CreateDummyDispatchThread0() + */ +JNIEXPORT jlong JNICALL +Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyDispatchThread0 + (JNIEnv *env, jclass _unused) +{ + DWORD threadId = 0; + DummyThreadContext * dispThreadCtx = calloc(1, sizeof(DummyThreadContext)); + + dispThreadCtx->threadHandle = CreateThread(NULL, 0, DummyDispatchThreadFunc, (LPVOID)dispThreadCtx, 0, &threadId); + if( NULL == dispThreadCtx->threadHandle || 0 == threadId ) { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT CREATE failed handle %p, id %d, werr %d", + (void*)threadHandle, (int)threadId, (int)GetLastError()); + return (jlong)0; + } + if( JNI_FALSE == DDT_WaitUntilCreated(env, dispThreadCtx, TRUE) ) { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT CREATE (ack) failed handle %p, id %d, werr %d", + (void*)threadHandle, (int)threadId, (int)GetLastError()); + return (jlong)0; + } + DBG_PRINT_FLUSH("*** DDT Created %d\n", (int)threadId); + dispThreadCtx->threadId = threadId; + return (jlong) (intptr_t) dispThreadCtx; +} + +/* Java->C glue code: + * Java package: jogamp.nativewindow.windows.GDIUtil + * Java method: boolean CreateWindowClass0(long hInstance, java.lang.String clazzName, long wndProc) + * C function: BOOL CreateWindowClass0(HANDLE hInstance, LPCSTR clazzName, HANDLE wndProc); */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass - (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName, jlong wndProc) +Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass0 + (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName, jlong wndProc, + jlong iconSmallHandle, jlong iconBigHandle) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; const TCHAR* clazzName = NULL; - WNDCLASS wc; + WNDCLASSEX wc; jboolean res; #ifdef UNICODE @@ -56,23 +252,25 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass #endif ZeroMemory( &wc, sizeof( wc ) ); - if( GetClassInfo( hInstance, clazzName, &wc ) ) { + if( GetClassInfoEx( hInstance, clazzName, &wc ) ) { // registered already res = JNI_TRUE; } else { // register now ZeroMemory( &wc, sizeof( wc ) ); + wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW ; wc.lpfnWndProc = (WNDPROC) (intptr_t) wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; - wc.hIcon = NULL; - wc.hCursor = LoadCursor( NULL, IDC_ARROW); + wc.hIcon = (HICON) (intptr_t) iconBigHandle; + wc.hCursor = NULL; wc.hbrBackground = NULL; // no background paint - GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = clazzName; - res = ( 0 != RegisterClass( &wc ) ) ? JNI_TRUE : JNI_FALSE ; + wc.hIconSm = (HICON) (intptr_t) iconSmallHandle; + res = ( 0 != RegisterClassEx( &wc ) ) ? JNI_TRUE : JNI_FALSE ; } #ifdef UNICODE @@ -86,15 +284,15 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass /* Java->C glue code: * Java package: jogamp.nativewindow.windows.GDIUtil - * Java method: boolean DestroyWindowClass(long hInstance, java.lang.String className) - * C function: BOOL DestroyWindowClass(HANDLE hInstance, LPCSTR className); + * Java method: boolean DestroyWindowClass0(long hInstance, java.lang.String className, long dispThreadCtx) */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass - (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName) +Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass0 + (JNIEnv *env, jclass gdiClazz, jlong jHInstance, jstring jClazzName, jlong jDispThreadCtx) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; const TCHAR* clazzName = NULL; + DummyThreadContext * dispThreadCtx = (DummyThreadContext *) (intptr_t) jDispThreadCtx; jboolean res; #ifdef UNICODE @@ -111,55 +309,175 @@ Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass (*env)->ReleaseStringUTFChars(env, jClazzName, clazzName); #endif + if( NULL != dispThreadCtx) { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + const DWORD threadId = dispThreadCtx->threadId; + DummyThreadCommand tParam = {0}; + tParam.threadReady = FALSE; + DBG_PRINT_FLUSH("*** DDT Destroy %d\n", (int)threadId); +#ifdef VERBOSE_ON + (*env)->CallStaticVoidMethod(env, gdiClazz, dumpStackID); +#endif + + if( JNI_FALSE == DDT_CheckAlive(env, sTM_STOP, dispThreadCtx) ) { + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT %s (alive) failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + if ( 0 != PostThreadMessage(dispThreadCtx->threadId, TM_STOP, (WPARAM)&tParam, 0) ) { + if( JNI_FALSE == DDT_WaitUntilReady(env, sTM_STOP, &tParam) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s (ack) failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + if( JNI_FALSE == DDT_WaitUntilCreated(env, dispThreadCtx, FALSE) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT KILL %s (ack) failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + free(dispThreadCtx); // free after proper DDT shutdown! + } else { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + } + return res; } - /* Java->C glue code: * Java package: jogamp.nativewindow.windows.GDIUtil - * Java method: long CreateDummyWindow0(long hInstance, java.lang.String className, java.lang.String windowName, int x, int y, int width, int height) - * C function: HANDLE CreateDummyWindow0(HANDLE hInstance, LPCSTR className, LPCSTR windowName, int x, int y, int width, int height); + * Java method: long CreateDummyWindow0(long hInstance, java.lang.String className, jlong dispThreadCtx, java.lang.String windowName, int x, int y, int width, int height) */ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyWindow0 - (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jWndClassName, jstring jWndName, jint x, jint y, jint width, jint height) + (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jWndClassName, jlong jDispThreadCtx, jstring jWndName, jint x, jint y, jint width, jint height) { - HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; - const TCHAR* wndClassName = NULL; - const TCHAR* wndName = NULL; - DWORD dwExStyle; - DWORD dwStyle; - HWND hWnd; + DummyThreadContext * dispThreadCtx = (DummyThreadContext *) (intptr_t) jDispThreadCtx; + DummyThreadCommand tParam = {0}; + + tParam.hInstance = (HINSTANCE) (intptr_t) jHInstance; + tParam.x = x; + tParam.y = y; + tParam.width = width; + tParam.height = height; + tParam.hWnd = 0; + tParam.threadReady = FALSE; #ifdef UNICODE - wndClassName = NewtCommon_GetNullTerminatedStringChars(env, jWndClassName); - wndName = NewtCommon_GetNullTerminatedStringChars(env, jWndName); + tParam.wndClassName = NewtCommon_GetNullTerminatedStringChars(env, jWndClassName); + tParam.wndName = NewtCommon_GetNullTerminatedStringChars(env, jWndName); #else - wndClassName = (*env)->GetStringUTFChars(env, jWndClassName, NULL); - wndName = (*env)->GetStringUTFChars(env, jWndName, NULL); + tParam.wndClassName = (*env)->GetStringUTFChars(env, jWndClassName, NULL); + tParam.wndName = (*env)->GetStringUTFChars(env, jWndName, NULL); #endif - dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - dwStyle = WS_OVERLAPPEDWINDOW; - - hWnd = CreateWindowEx( dwExStyle, - wndClassName, - wndName, - dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - x, y, width, height, - NULL, NULL, hInstance, NULL ); + if( NULL == dispThreadCtx ) { + tParam.hWnd = DummyWindowCreate(tParam.hInstance, tParam.wndClassName, tParam.wndName, tParam.x, tParam.y, tParam.width, tParam.height); + } else { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + const DWORD threadId = dispThreadCtx->threadId; + if( JNI_FALSE == DDT_CheckAlive(env, sTM_OPENWIN, dispThreadCtx) ) { + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT %s (alive) failed handle %p, id %d, werr %d", + sTM_OPENWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } else { + if( 0 != PostThreadMessage(dispThreadCtx->threadId, TM_OPENWIN, (WPARAM)&tParam, 0) ) { + if( JNI_FALSE == DDT_WaitUntilReady(env, sTM_OPENWIN, &tParam) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + tParam.hWnd = 0; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s (ack) failed handle %p, id %d, werr %d", + sTM_OPENWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } else { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + tParam.hWnd = 0; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s to handle %p, id %d failed, werr %d", + sTM_OPENWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } + } #ifdef UNICODE - free((void*) wndClassName); - free((void*) wndName); + free((void*) tParam.wndClassName); + free((void*) tParam.wndName); #else - (*env)->ReleaseStringUTFChars(env, jWndClassName, wndClassName); - (*env)->ReleaseStringUTFChars(env, jWndName, wndName); + (*env)->ReleaseStringUTFChars(env, jWndClassName, tParam.wndClassName); + (*env)->ReleaseStringUTFChars(env, jWndName, tParam.wndName); #endif - return (jlong) (intptr_t) hWnd; + return (jlong) (intptr_t) tParam.hWnd; } +/* + * Class: jogamp_nativewindow_windows_GDIUtil + * Method: DestroyWindow0 + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindow0 +(JNIEnv *env, jclass unused, jlong jDispThreadCtx, jlong jwin) +{ + jboolean res = JNI_TRUE; + DummyThreadContext * dispThreadCtx = (DummyThreadContext *) (intptr_t) jDispThreadCtx; + HWND hWnd = (HWND) (intptr_t) jwin; + if( NULL == dispThreadCtx ) { + DestroyWindow(hWnd); + } else { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + const DWORD threadId = dispThreadCtx->threadId; + DummyThreadCommand tParam = {0}; + + tParam.hWnd = hWnd; + tParam.threadReady = FALSE; + + if( JNI_FALSE == DDT_CheckAlive(env, sTM_CLOSEWIN, dispThreadCtx) ) { + free(dispThreadCtx); + res = JNI_FALSE; + NativewindowCommon_throwNewRuntimeException(env, "DDT %s (alive) failed handle %p, id %d, werr %d", + sTM_CLOSEWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } else { + if ( 0 != PostThreadMessage(dispThreadCtx->threadId, TM_CLOSEWIN, (WPARAM)&tParam, 0) ) { + if( JNI_FALSE == DDT_WaitUntilReady(env, sTM_CLOSEWIN, &tParam) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + res = JNI_FALSE; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s (ack) failed handle %p, id %d, werr %d", + sTM_CLOSEWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } else { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + res = JNI_FALSE; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s to handle %p, id %d failed, werr %d", + sTM_CLOSEWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } + } + return res; +} /* * Class: jogamp_nativewindow_windows_GDIUtil @@ -167,9 +485,9 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyWindow0 * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 - (JNIEnv *env, jclass clazz) + (JNIEnv *env, jclass gdiClazz) { - if(NativewindowCommon_init(env)) { + if( NativewindowCommon_init(env) ) { jclass c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't find %s", ClazzNamePoint); @@ -184,12 +502,16 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't fetch %s.%s %s", ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } + dumpStackID = (*env)->GetStaticMethodID(env, gdiClazz, "dumpStack", "()V"); + if(NULL==dumpStackID) { + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't get method dumpStack"); + } } return JNI_TRUE; } -LRESULT CALLBACK DummyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return DefWindowProc(hWnd,uMsg,wParam,lParam); +static LRESULT CALLBACK DummyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + return DefWindowProc(hWnd,uMsg,wParam,lParam); } /* @@ -224,3 +546,133 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_windows_GDIUtil_GetRelativeLo return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest.x, (jint)dest.y); } +/* + * Class: jogamp_nativewindow_windows_GDIUtil + * Method: IsChild0 + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_IsChild0 + (JNIEnv *env, jclass unused, jlong jwin) +{ + HWND hWnd = (HWND) (intptr_t) jwin; + LONG style = GetWindowLong(hWnd, GWL_STYLE); + BOOL bIsChild = 0 != (style & WS_CHILD) ; + return bIsChild ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: jogamp_nativewindow_windows_GDIUtil + * Method: IsUndecorated0 + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_IsUndecorated0 + (JNIEnv *env, jclass unused, jlong jwin) +{ + HWND hWnd = (HWND) (intptr_t) jwin; + LONG style = GetWindowLong(hWnd, GWL_STYLE); + BOOL bIsUndecorated = 0 != (style & (WS_CHILD|WS_POPUP)) ; + return bIsUndecorated ? JNI_TRUE : JNI_FALSE; +} + +#if 0 + +#include <tlhelp32.h> +#include <tchar.h> + +static void printError( TCHAR* msg ) +{ + DWORD eNum; + TCHAR sysMsg[256]; + TCHAR* p; + + eNum = GetLastError( ); + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, eNum, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + sysMsg, 256, NULL ); + + // Trim the end of the line and terminate it with a null + p = sysMsg; + while( ( *p > 31 ) || ( *p == 9 ) ) + ++p; + do { *p-- = 0; } while( ( p >= sysMsg ) && + ( ( *p == '.' ) || ( *p < 33 ) ) ); + + // Display the message + _ftprintf(stderr, TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg ); +} + +static BOOL SetProcessThreadsAffinityMask( DWORD dwOwnerPID, DWORD_PTR newTAffinity, BOOL verbose ) +{ + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + DWORD_PTR preTAffinity; + HANDLE threadHandle; + + // Take a snapshot of all running threads + hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( hThreadSnap == INVALID_HANDLE_VALUE ) + return( FALSE ); + + // Fill in the size of the structure before using it. + te32.dwSize = sizeof(THREADENTRY32 ); + + // Retrieve information about the first thread, + // and exit if unsuccessful + if( !Thread32First( hThreadSnap, &te32 ) ) + { + if( verbose ) { + printError( TEXT("Thread32First") ); // Show cause of failure + } + CloseHandle( hThreadSnap ); // Must clean up the snapshot object! + return( FALSE ); + } + + // Now walk the thread list of the system, + // and display information about each thread + // associated with the specified process + do + { + if( te32.th32OwnerProcessID == dwOwnerPID ) + { + if( verbose ) { + _ftprintf(stderr, TEXT("\n THREAD ID = 0x%08X, %d"), te32.th32ThreadID, te32.th32ThreadID); + _ftprintf(stderr, TEXT("\n base priority = %d"), te32.tpBasePri ); + _ftprintf(stderr, TEXT("\n delta priority = %d"), te32.tpDeltaPri ); + } + threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); + if( NULL != threadHandle ) { + preTAffinity = SetThreadAffinityMask(threadHandle, newTAffinity); + CloseHandle(threadHandle); + if( verbose ) { + _ftprintf(stderr, TEXT("\n affinity %p -> %p"), preTAffinity, newTAffinity); + } + } else { + if( verbose ) { + _ftprintf(stderr, TEXT("\n OpenThread failed %d"), (int)GetLastError()); + } + } + } + } while( Thread32Next(hThreadSnap, &te32 ) ); + + if( verbose ) { + _ftprintf(stderr, TEXT("\n")); + } + +// Don't forget to clean up the snapshot object. + CloseHandle( hThreadSnap ); + return( TRUE ); +} + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_windows_GDIUtil_SetProcessThreadsAffinityMask0 + (JNIEnv *env, jclass unused, jlong affinityMask, jboolean verbose) +{ + SetProcessThreadsAffinityMask( GetCurrentProcessId(), (DWORD_PTR)(intptr_t)affinityMask, (BOOL)verbose ); +} + +#else + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_windows_GDIUtil_SetProcessThreadsAffinityMask0 + (JNIEnv *env, jclass unused, jlong affinityMask, jboolean verbose) +{ +} + +#endif diff --git a/src/nativewindow/native/win32/WindowsDWM.h b/src/nativewindow/native/win32/WindowsDWM.h index 36f82fc94..6e5160fa4 100644 --- a/src/nativewindow/native/win32/WindowsDWM.h +++ b/src/nativewindow/native/win32/WindowsDWM.h @@ -4,6 +4,8 @@ #include <windows.h> #define DWM_BB_ENABLE 0x00000001 // fEnable has been specified + #define DWM_BB_BLURREGION 0x00000002 + #define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 #define DWM_EC_DISABLECOMPOSITION 0 #define DWM_EC_ENABLECOMPOSITION 1 diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index fcba8580c..247dc1311 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -29,6 +29,14 @@ #include "NativewindowCommon.h" #include "Xmisc.h" #include "jogamp_nativewindow_x11_X11Lib.h" +#include "jogamp_nativewindow_x11_X11Util.h" + +#include <X11/Xatom.h> + +#include <X11/extensions/Xrender.h> + +/** Remove memcpy GLIBC > 2.4 dependencies */ +#include <glibc-compat-symbols.h> // #define VERBOSE_ON 1 @@ -84,6 +92,8 @@ Bool XF86VidModeSetGammaRamp( #define RTLD_DEFAULT NULL #endif +#define X11_MOUSE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask) + static const char * const ClazzNameBuffers = "com/jogamp/common/nio/Buffers"; static const char * const ClazzNameBuffersStaticCstrName = "copyByteBuffer"; static const char * const ClazzNameBuffersStaticCstrSignature = "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"; @@ -103,128 +113,116 @@ static jmethodID pointCstr = NULL; static void _initClazzAccess(JNIEnv *env) { jclass c; - if(!NativewindowCommon_init(env)) return; - - getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;"); - if(NULL==getCurrentThreadNameID) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName"); - } - dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V"); - if(NULL==dumpStackID) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack"); - } - - c = (*env)->FindClass(env, ClazzNameBuffers); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); - } - clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==clazzBuffers) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers); - } - c = (*env)->FindClass(env, ClazzNameByteBuffer); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer); - } - clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer); - } - - cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers, - ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); - if(NULL==cstrBuffers) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s", - ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); - } + if( NativewindowCommon_init(env) ) { + getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;"); + if(NULL==getCurrentThreadNameID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName"); + } + dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V"); + if(NULL==dumpStackID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack"); + } - c = (*env)->FindClass(env, ClazzNamePoint); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint); - } - pointClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==pointClz) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint); - } - pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); - if(NULL==pointCstr) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s", - ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); - } -} + c = (*env)->FindClass(env, ClazzNameBuffers); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); + } + clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==clazzBuffers) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers); + } + c = (*env)->FindClass(env, ClazzNameByteBuffer); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer); + } + clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer); + } -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; + cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers, + ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); + if(NULL==cstrBuffers) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s", + ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); + } -static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + c = (*env)->FindClass(env, ClazzNamePoint); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint); + } + pointClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==pointClz) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint); + } + pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); + if(NULL==pointCstr) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s", + ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); + } } - jvmVersion = (*env)->GetVersion(env); } static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerQuiet = 0 ; +static int errorHandlerQuiet = 1 ; static int errorHandlerDebug = 0 ; static int errorHandlerThrowException = 0; static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { - if(!errorHandlerQuiet) { + if( !errorHandlerQuiet || errorHandlerDebug ) { const char * errnoStr = strerror(errno); - char threadName[80]; char errCodeStr[80]; char reqCodeStr[80]; - int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv *jniEnv = NULL; - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); - fprintf(stderr, "Info: Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + fprintf(stderr, "Info: Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); + fflush(stderr); - if( errorHandlerDebug ) { - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); - } - - if(errorHandlerThrowException) { - if(NULL != jniEnv) { - NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - } else { + if( errorHandlerDebug || errorHandlerThrowException ) { + jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached); + if(NULL == jniEnv) { fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); - #if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } - #endif + fflush(stderr); } } - fflush(stderr); - if (NULL != jniEnv && shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); + if( NULL != jniEnv ) { + if( errorHandlerDebug ) { + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + } + + if(errorHandlerThrowException) { + NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + (int)e->request_code, (int)e->minor_code, reqCodeStr); + } + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } } return 0; } -void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { +static void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int force, int onoff, int quiet, int sync) { errorHandlerQuiet = quiet; if(onoff) { - if(NULL==origErrorHandler) { - setupJVMVars(env); - origErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(force || NULL==origErrorHandler) { + XErrorHandler prevErrorHandler; + prevErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(x11ErrorHandler != prevErrorHandler) { // if forced don't overwrite w/ orig w/ our handler + origErrorHandler = prevErrorHandler; + } if(sync && NULL!=dpy) { XSync(dpy, False); } @@ -246,21 +244,16 @@ static int x11IOErrorHandler(Display *dpy) { const char * dpyName = XDisplayName(NULL); const char * errnoStr = strerror(errno); - char threadName[80]; int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv *jniEnv = NULL; - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - - fprintf(stderr, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s\n", threadName, dpy, dpyName, errnoStr); - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr); + fflush(stderr); + jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached); if (NULL != jniEnv) { - NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); - - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr); + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } if(NULL!=origIOErrorHandler) { origIOErrorHandler(dpy); @@ -271,7 +264,6 @@ static int x11IOErrorHandler(Display *dpy) static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { if(onoff) { if(NULL==origIOErrorHandler) { - setupJVMVars(env); origIOErrorHandler = XSetIOErrorHandler(x11IOErrorHandler); } } else { @@ -280,47 +272,49 @@ static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { } } -static int _initialized=0; -static jboolean _xinitThreadsOK=JNI_FALSE; +static int _initialized = 0; JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboolean firstUIActionOnProcess, jboolean debug) { - if(0==_initialized) { +Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboolean debug) { + if( 0 == _initialized ) { if(debug) { errorHandlerDebug = 1; } X11UtilClazz = (jclass)(*env)->NewGlobalRef(env, clazz); - if( JNI_TRUE == firstUIActionOnProcess ) { - if( 0 == XInitThreads() ) { - fprintf(stderr, "Warning: XInitThreads() failed\n"); - } else { - _xinitThreadsOK=JNI_TRUE; - if(debug) { - fprintf(stderr, "X11: XInitThreads() called for concurrent Thread support\n"); - } - } - } else if(debug) { - fprintf(stderr, "X11: XInitThreads() _not_ called for concurrent Thread support\n"); - } _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 1, debug ? 0 : 1, 0 /* no dpy, force, no sync */); _initialized=1; if(JNI_TRUE == debug) { fprintf(stderr, "Info: NativeWindow native init passed\n"); } } - return _xinitThreadsOK; + return JNI_TRUE; } JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0 /* no dpy, no sync */); x11IOErrorHandlerEnable(0, env); } JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _unused, jboolean onoff, jboolean quiet) { - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, force, no sync */); +} + +/* Java->C glue code: + * Java package: jogamp.nativewindow.x11.X11Lib + * Java method: boolean XRenderFindVisualFormat(long dpy, long visual, XRenderPictFormat dest) + */ +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_x11_X11Lib_XRenderFindVisualFormat1(JNIEnv *env, jclass _unused, jlong dpy, jlong visual, jobject xRenderPictFormat) { + XRenderPictFormat * dest = (XRenderPictFormat *) (*env)->GetDirectBufferAddress(env, xRenderPictFormat); + XRenderPictFormat * src = XRenderFindVisualFormat((Display *) (intptr_t) dpy, (Visual *) (intptr_t) visual); + if (NULL == src) return JNI_FALSE; + memcpy(dest, src, sizeof(XRenderPictFormat)); + return JNI_TRUE; } /* Java->C glue code: @@ -332,30 +326,30 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(JNIEnv *env, jclass _unused, jlong arg0, jlong arg1, jobject arg2, jobject arg3, jint arg3_byte_offset) { XVisualInfo * _ptr2 = NULL; int * _ptr3 = NULL; - XVisualInfo * _res; - int count; - jobject jbyteSource; - jobject jbyteCopy; - if(0==arg0) { - NativewindowCommon_FatalError(env, "invalid display connection.."); - } - if (arg2 != NULL) { - _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0); - } - if (arg3 != NULL) { - _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); + XVisualInfo * _res = NULL; + int count = 0; + jobject jbyteSource = NULL; + jobject jbyteCopy = NULL; + if( 0 == arg0 || 0 == arg2 || 0 == arg3 ) { + NativewindowCommon_FatalError(env, "invalid display connection, vinfo_template or nitems_return"); + return NULL; } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); - _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); - count = _ptr3[0]; - if (arg3 != NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); + _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0); + if( NULL != _ptr2 ) { + _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); + if( NULL != _ptr3 ) { + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, errorHandlerQuiet, 0); + _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, errorHandlerQuiet, 0); + count = _ptr3[0]; + (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); + } } if (_res == NULL) return NULL; jbyteSource = (*env)->NewDirectByteBuffer(env, _res, count * sizeof(XVisualInfo)); jbyteCopy = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffers, jbyteSource); + (*env)->DeleteLocalRef(env, jbyteSource); XFree(_res); @@ -371,10 +365,10 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u if(NULL==dpy) { NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); - return; + return 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 1); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 1); memset(&xwa, 0, sizeof(XWindowAttributes)); XGetWindowAttributes(dpy, w, &xwa); if(NULL != xwa.visual) { @@ -382,7 +376,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u } else { r = 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); return r; } @@ -394,9 +388,9 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 1, errorHandlerQuiet, 0); r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, errorHandlerQuiet, 0); return r; } @@ -437,23 +431,68 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 1, errorHandlerQuiet, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0); return _res; } +static void NativewindowX11_setNormalWindowEWMH (Display *dpy, Window w) { + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[1]={0}; + types[0] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1); + XSync(dpy, False); +} + +#define DECOR_USE_MWM 1 // works for known WMs +// #define DECOR_USE_EWMH 1 // haven't seen this to work (NORMAL->POPUP, never gets undecorated) + +/* see <http://tonyobryan.com/index.php?article=9> */ +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 + +static void NativewindowX11_setDecorations (Display *dpy, Window w, Bool decorated) { + +#ifdef DECOR_USE_MWM + unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status + Atom _MOTIF_WM_HINTS = XInternAtom( dpy, "_MOTIF_WM_HINTS", False ); +#endif + +#ifdef DECOR_USE_EWMH + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[3]={0}; + int ntypes=0; + if(True==decorated) { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + } else { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False ); + } +#endif + +#ifdef DECOR_USE_MWM + XChangeProperty( dpy, w, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS); +#endif + +#ifdef DECOR_USE_EWMH + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); +#endif + + XSync(dpy, False); +} + /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: CreateDummyWindow - * Signature: (JIIII)J + * Method: CreateWindow + * Signature: (JJIIIIZZ)J */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow - (JNIEnv *env, jclass unused, jlong display, jint screen_index, jint visualID, jint width, jint height) +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow + (JNIEnv *env, jclass unused, jlong parent, jlong display, jint screen_index, jint visualID, jint width, jint height, jboolean input, jboolean visible) { Display * dpy = (Display *)(intptr_t)display; int scrn_idx = (int)screen_index; - Window windowParent = 0; + Window root = RootWindow(dpy, scrn_idx); + Window windowParent = (Window) parent; Window window = 0; XVisualInfo visualTemplate; @@ -477,9 +516,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow return 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); + if(0==windowParent) { + windowParent = root; + } // try given VisualID on screen memset(&visualTemplate, 0, sizeof(XVisualInfo)); @@ -497,7 +539,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -507,9 +549,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow pVisualQuery=NULL; } - if(0==windowParent) { - windowParent = XRootWindowOfScreen(scrn); - } attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap | CWBorderPixel | CWColormap | CWOverrideRedirect ) ; @@ -521,15 +560,22 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow xswa.backing_store=NotUseful; /* NotUseful, WhenMapped, Always */ xswa.backing_planes=0; /* planes to be preserved if possible */ xswa.backing_pixel=0; /* value to use in restoring planes */ + if( input ) { + xswa.event_mask = X11_MOUSE_EVENT_MASK; + xswa.event_mask |= KeyPressMask | KeyReleaseMask ; + } + if( visible ) { + xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ; + } xswa.colormap = XCreateColormap(dpy, - XRootWindow(dpy, scrn_idx), + windowParent, visual, AllocNone); window = XCreateWindow(dpy, windowParent, - 0, 0, + 0, 0, // only a hint, WM most likely will override width, height, 0, // border width depth, @@ -537,11 +583,27 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow visual, attrMask, &xswa); + if(0==window) { + NativewindowCommon_throwNewRuntimeException(env, "could not create Window, bail out!"); + return 0; + } + + NativewindowX11_setNormalWindowEWMH(dpy, window); + NativewindowX11_setDecorations(dpy, window, False); + + if( visible ) { + XEvent event; + + XMapWindow(dpy, window); + } + XSync(dpy, False); - XSelectInput(dpy, window, 0); // no events + if( !input ) { + XSelectInput(dpy, window, 0); // no events + } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -551,25 +613,57 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: DestroyDummyWindow + * Method: DestroyWindow * Signature: (JJ)V */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow (JNIEnv *env, jclass unused, jlong display, jlong window) { Display * dpy = (Display *)(intptr_t)display; Window w = (Window) window; + XWindowAttributes xwa; if(NULL==dpy) { NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); return; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); + XSync(dpy, False); + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, w, &xwa); // prefetch colormap to be destroyed after window destruction + XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + if( None != xwa.colormap ) { + XFreeColormap(dpy, xwa.colormap); + } + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); +} + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize + (JNIEnv *env, jclass unused, jlong display, jlong window, jint x, jint y, jint width, jint height) { + Display * dpy = (Display *)(intptr_t)display; + Window w = (Window) window; + XWindowChanges xwc; + int flags = 0; + + memset(&xwc, 0, sizeof(XWindowChanges)); + + if(0<=x && 0<=y) { + flags |= CWX | CWY; + xwc.x=x; + xwc.y=y; + } + + if(0<width && 0<height) { + flags |= CWWidth | CWHeight; + xwc.width=width; + xwc.height=height; + } + XConfigureWindow(dpy, w, flags, &xwc); + XSync(dpy, False); } /* @@ -593,11 +687,11 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio if( 0 == jdest_win ) { dest_win = root; } if( 0 == jsrc_win ) { src_win = root; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); @@ -605,3 +699,38 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y); } +/* + * Class: jogamp_nativewindow_x11_X11Lib + * Method: QueryExtension0 + * Signature: (JLjava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Lib_QueryExtension0 + (JNIEnv *env, jclass unused, jlong jdisplay, jstring jextensionName) +{ + int32_t major_opcode, first_event, first_error; + jboolean res = JNI_FALSE; + Display * display = (Display *) (intptr_t) jdisplay; + const char* extensionName = NULL; + + if(NULL==display) { + NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"display\""); + return res; + } + if ( NULL == jextensionName ) { + NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"extensionName\""); + return res; + } + extensionName = (*env)->GetStringUTFChars(env, jextensionName, (jboolean*)NULL); + if ( NULL == extensionName ) { + NativewindowCommon_throwNewRuntimeException(env, "Failed to get UTF-8 chars for argument \"extensionName\""); + return res; + } + + res = True == XQueryExtension(display, extensionName, &major_opcode, &first_event, &first_error) ? JNI_TRUE : JNI_FALSE; + + if ( NULL != jextensionName ) { + (*env)->ReleaseStringUTFChars(env, jextensionName, extensionName); + } + return res; +} + diff --git a/src/nativewindow/native/x11/Xmisc.h b/src/nativewindow/native/x11/Xmisc.h index a44da950d..91f2ac5d9 100644 --- a/src/nativewindow/native/x11/Xmisc.h +++ b/src/nativewindow/native/x11/Xmisc.h @@ -39,6 +39,4 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> -void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); - #endif /* Xmisc_h */ |