diff options
Diffstat (limited to 'src/nativewindow/classes/jogamp')
23 files changed, 1244 insertions, 549 deletions
diff --git a/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java b/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java new file mode 100644 index 000000000..ee3ab73ba --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java @@ -0,0 +1,43 @@ +/** + * 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. + */ +package jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.DefaultGraphicsConfiguration; + +public class MutableGraphicsConfiguration extends DefaultGraphicsConfiguration { + public MutableGraphicsConfiguration(AbstractGraphicsScreen screen, + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + super(screen, capsChosen, capsRequested); + } + + public void setChosenCapabilities(CapabilitiesImmutable caps) { + super.setChosenCapabilities(caps); + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java index 2b6d3c016..4cf8f448e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java @@ -33,6 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.jvm.JNILibLoaderBase; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.cache.TempJarCache; public class NWJNILibLoader extends JNILibLoaderBase { @@ -40,9 +41,10 @@ public class NWJNILibLoader extends JNILibLoaderBase { public static void loadNativeWindow(final String ossuffix) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { + Platform.initSingleton(); final String libName = "nativewindow_"+ossuffix ; if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { - addNativeJarLibs(NWJNILibLoader.class, "jogl.all", "jogl-all", new String[] { "nativewindow" } ); + addNativeJarLibs(NWJNILibLoader.class, "jogl-all", new String[] { "nativewindow" } ); } loadLibrary(libName, false); return null; diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index d34d4e58f..223078ebf 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -32,11 +32,15 @@ package jogamp.nativewindow; -import com.jogamp.common.os.Platform; -import com.jogamp.common.util.*; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ToolkitLock; -import javax.media.nativewindow.*; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.ReflectionUtil; public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); @@ -44,13 +48,10 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { public static ToolkitLock getNullToolkitLock() { return nullToolkitLock; } - + // This subclass of NativeWindowFactory handles the case of // NativeWindows being passed in protected NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException { - if (null == winObj) { - throw new IllegalArgumentException("winObj is null"); - } if (winObj instanceof NativeWindow) { // Use the NativeWindow directly return (NativeWindow) winObj; @@ -69,7 +70,7 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { "javax.media.nativewindow.NativeWindow or "+AWTComponentClassName); } - private Constructor nativeWindowConstructor = null; + private Constructor<?> nativeWindowConstructor = null; private NativeWindow getAWTNativeWindow(Object winObj, AbstractGraphicsConfiguration config) { if (nativeWindowConstructor == null) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java new file mode 100644 index 000000000..4877d5c4f --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java @@ -0,0 +1,85 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.nativewindow; + +import java.util.ArrayList; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.SurfaceUpdatedListener; + +public class SurfaceUpdatedHelper implements SurfaceUpdatedListener { + private Object surfaceUpdatedListenersLock = new Object(); + private ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); + + // + // Management Utils + // + public int size() { return surfaceUpdatedListeners.size(); } + public SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); } + + // + // Implementation of NativeSurface SurfaceUpdatedListener methods + // + + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + addSurfaceUpdatedListener(-1, l); + } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size(); + } + surfaceUpdatedListeners.add(index, l); + } + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + if (l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners.remove(l); + } + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + synchronized(surfaceUpdatedListenersLock) { + for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { + SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); + l.surfaceUpdated(updater, ns, when); + } + } + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index 4c2b1c875..074fab563 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -33,7 +33,7 @@ import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.SurfaceChangeable; -public class WrappedSurface extends ProxySurface implements SurfaceChangeable { +public class WrappedSurface extends ProxySurface implements SurfaceChangeable { protected long surfaceHandle; public WrappedSurface(AbstractGraphicsConfiguration cfg) { @@ -65,6 +65,10 @@ public class WrappedSurface extends ProxySurface implements SurfaceChangeable { } public String toString() { - return "WrappedSurface[config " + config + ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + ", size " + getWidth() + "x" + getHeight() + "]"; + return "WrappedSurface[config " + getPrivateGraphicsConfiguration()+ + ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + + ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + + ", size " + getWidth() + "x" + getHeight() + + ", surfaceLock "+surfaceLock+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java index 2c8538278..354bb83e3 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java @@ -40,14 +40,15 @@ package jogamp.nativewindow.jawt; import javax.media.nativewindow.NativeWindowFactory; + import jogamp.nativewindow.NWJNILibLoader; import java.awt.Toolkit; import java.security.AccessController; import java.security.PrivilegedAction; -public class JAWTJNILibLoader extends NWJNILibLoader { - public static void loadAWTImpl() { +public class JAWTJNILibLoader extends NWJNILibLoader { + static { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { // Make sure that awt.dll is loaded before loading jawt.dll. Otherwise @@ -73,4 +74,9 @@ public class JAWTJNILibLoader extends NWJNILibLoader { } }); } + + public static void initSingleton() { + // 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 c1c97eece..21e9a3e09 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -37,24 +37,28 @@ package jogamp.nativewindow.jawt; -import jogamp.nativewindow.*; import java.awt.EventQueue; - -import javax.media.nativewindow.*; - - import java.awt.GraphicsEnvironment; import java.awt.Toolkit; -import java.lang.reflect.*; -import java.security.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Map; +import javax.media.nativewindow.NativeWindowException; + +import jogamp.nativewindow.Debug; + +import com.jogamp.common.os.Platform; + public class JAWTUtil { protected static final boolean DEBUG = Debug.debug("JAWT"); // See whether we're running in headless mode private static final boolean headlessMode; + private static final JAWT jawtLockObject; // Java2D magic .. private static final Method isQueueFlusherThread; @@ -75,31 +79,67 @@ public class JAWTUtil { boolean ok; } + /** + * Returns true if this platform's JAWT implementation supports + * or uses offscreen layer. + */ + public static boolean isOffscreenLayerSupported() { + return Platform.OS_TYPE == Platform.OSType.MACOS && + Platform.OS_VERSION_NUMBER.compareTo(JAWT.JAWT_MacOSXCALayerMinVersion) >= 0; + } + + /** + * @param useOffscreenLayerIfAvailable + * @return + */ + public static JAWT getJAWT(boolean useOffscreenLayerIfAvailable) { + int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; + if(useOffscreenLayerIfAvailable) { + switch(Platform.OS_TYPE) { + case MACOS: + if(Platform.OS_VERSION_NUMBER.compareTo(JAWT.JAWT_MacOSXCALayerMinVersion) >= 0) { + jawt_version_flags |= JAWT.JAWT_MACOSX_USE_CALAYER; + } + } + } + return JAWT.getJAWT(jawt_version_flags); + } + + public static boolean isJAWTUsingOffscreenLayer(JAWT jawt) { + return 0 != ( jawt.getCachedVersion() & JAWT.JAWT_MACOSX_USE_CALAYER ); + } + static { - JAWTJNILibLoader.loadAWTImpl(); + if(DEBUG) { + System.err.println("JAWTUtil initialization (JAWT/JNI/..."); + // Thread.dumpStack(); + } + JAWTJNILibLoader.initSingleton(); JAWTJNILibLoader.loadNativeWindow("awt"); headlessMode = GraphicsEnvironment.isHeadless(); - boolean ok = false; - Class jC = null; + Class<?> jC = null; Method m = null; if (!headlessMode) { + jawtLockObject = getJAWT(false); // don't care for offscreen layer here try { jC = Class.forName("jogamp.opengl.awt.Java2D"); m = jC.getMethod("isQueueFlusherThread", (Class[])null); ok = true; } catch (Exception e) { } + } else { + jawtLockObject = null; // headless ! } isQueueFlusherThread = m; j2dExist = ok; - PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction() { + PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); try { - final Class sunToolkitClass = Class.forName("sun.awt.SunToolkit"); + 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[]{}); @@ -129,21 +169,21 @@ public class JAWTUtil { jawtToolkitLock = new JAWTToolkitLock(); // trigger native AWT toolkit / properties initialization - Map desktophints = null; + Map<?,?> desktophints = null; try { if(EventQueue.isDispatchThread()) { - desktophints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); } else { - final ArrayList desktophintsBucket = new ArrayList(1); + final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1); EventQueue.invokeAndWait(new Runnable() { public void run() { - Map _desktophints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if(null!=_desktophints) { desktophintsBucket.add(_desktophints); } } }); - desktophints = ( desktophintsBucket.size() > 0 ) ? (Map)desktophintsBucket.get(0) : null ; + desktophints = ( desktophintsBucket.size() > 0 ) ? desktophintsBucket.get(0) : null ; } } catch (InterruptedException ex) { ex.printStackTrace(); @@ -189,7 +229,7 @@ public class JAWTUtil { * JAWT's native Lock() function calls SunToolkit.awtLock(), * which just uses AWT's global ReentrantLock.<br> */ - public static void awtLock() { + private static void awtLock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTLockMethod.invoke(null, (Object[])null); @@ -197,7 +237,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtLock failed", e); } } else { - JAWT.getJAWT().Lock(); + jawtLockObject.Lock(); } } @@ -207,7 +247,7 @@ public class JAWTUtil { * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), * which just uses AWT's global ReentrantLock.<br> */ - public static void awtUnlock() { + private static void awtUnlock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); @@ -215,7 +255,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtUnlock failed", e); } } else { - JAWT.getJAWT().Unlock(); + jawtLockObject.Unlock(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java index 2c80392ad..be697b3e0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java @@ -41,73 +41,190 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; import java.awt.Component; -import java.awt.Window; +import java.awt.Container; +import java.applet.Applet; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; -public abstract class JAWTWindow implements NativeWindow { +import jogamp.nativewindow.SurfaceUpdatedHelper; + +public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption { protected static final boolean DEBUG = JAWTUtil.DEBUG; + // user properties + protected boolean shallUseOffscreenLayer = false; + // lifetime: forever protected Component component; - protected AbstractGraphicsConfiguration config; + private AWTGraphicsConfiguration config; // control access due to delegation + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - // lifetime: valid after lock, forever until invalidate + // lifetime: valid after lock but may change with each 1st lock, purges after invalidate + private boolean isApplet; + private JAWT jawt; + private boolean isOffscreenLayerSurface; protected long drawable; protected Rectangle bounds; - - public JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + protected Insets insets; + + /** + * Constructed by {@link jogamp.nativewindow.NativeWindowFactoryImpl#getNativeWindow(Object, AbstractGraphicsConfiguration)} + * via this platform's specialization (X11, OSX, Windows, ..). + * + * @param comp + * @param config + */ + protected JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { if (config == null) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is null"); } - this.config = config; + if(! ( config instanceof AWTGraphicsConfiguration ) ) { + throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config); + } + this.config = (AWTGraphicsConfiguration) config; init((Component)comp); } private void init(Component windowObject) throws NativeWindowException { invalidate(); this.component = windowObject; - validateNative(); + this.isApplet = false; } - protected abstract void validateNative() throws NativeWindowException; - + + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + public final boolean isOffscreenLayerSurfaceEnabled() { + return isOffscreenLayerSurface; + } + protected synchronized void invalidate() { - component = null; + invalidateNative(); + jawt = null; + isOffscreenLayerSurface = false; drawable= 0; bounds = new Rectangle(); + insets = new Insets(); } + protected abstract void invalidateNative(); protected final void updateBounds(JAWT_Rectangle jawtBounds) { bounds.setX(jawtBounds.getX()); bounds.setY(jawtBounds.getY()); bounds.setWidth(jawtBounds.getWidth()); bounds.setHeight(jawtBounds.getHeight()); + + if(component instanceof Container) { + java.awt.Insets contInsets = ((Container)component).getInsets(); + insets.setLeftWidth(contInsets.left); + insets.setRightWidth(contInsets.right); + insets.setTopHeight(contInsets.top); + insets.setBottomHeight(contInsets.bottom); + } } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } - public final InsetsImmutable getInsets() { return Insets.getZero(); } + public final InsetsImmutable getInsets() { return insets; } public final Component getAWTComponent() { return component; } + + /** + * Returns true if the AWT component is parented to an {@link java.applet.Applet}, + * otherwise false. This information is valid only after {@link #lockSurface()}. + */ + public final boolean isApplet() { + return isApplet; + } + /** Returns the underlying JAWT instance created @ {@link #lockSurface()}. */ + public final JAWT getJAWT() { + return jawt; + } + + /** + * {@inheritDoc} + */ + public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new NativeWindowException("Not an offscreen layer surface"); + } + int lockRes = lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock (offscreen layer): "+this); + } + try { + if(DEBUG) { + System.err.println("JAWTWindow.attachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); + } + attachSurfaceLayerImpl(layerHandle); + } finally { + unlockSurface(); + } + } + protected abstract void attachSurfaceLayerImpl(final long layerHandle); + + /** + * {@inheritDoc} + */ + public final void detachSurfaceLayer(final long layerHandle) throws NativeWindowException { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new java.lang.UnsupportedOperationException("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.detachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); + } + detachSurfaceLayerImpl(layerHandle); + } finally { + unlockSurface(); + } + } + protected abstract void detachSurfaceLayerImpl(final long layerHandle); + // // SurfaceUpdateListener // - public final void surfaceUpdated(Object updater, NativeSurface ns, long when) { - // nop + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } // // NativeSurface @@ -115,6 +232,24 @@ public abstract class JAWTWindow implements NativeWindow { private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private void determineIfApplet() { + Component c = component; + while(!isApplet && null != c) { + isApplet = c instanceof Applet; + c = c.getParent(); + } + } + + /** + * If JAWT offscreen layer is supported, + * implementation shall respect {@link #getShallUseOffscreenLayer()} + * and may respect {@link #isApplet()}. + * + * @return The JAWT instance reflecting offscreen layer support, etc. + * + * @throws NativeWindowException + */ + protected abstract JAWT fetchJAWTImpl() throws NativeWindowException; protected abstract int lockSurfaceImpl() throws NativeWindowException; public final int lockSurface() throws NativeWindowException { @@ -122,10 +257,13 @@ public abstract class JAWTWindow implements NativeWindow { int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { + determineIfApplet(); try { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); adevice.lock(); try { + jawt = fetchJAWTImpl(); + isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); res = lockSurfaceImpl(); } finally { if (LOCK_SURFACE_NOT_READY >= res) { @@ -147,7 +285,7 @@ public abstract class JAWTWindow implements NativeWindow { surfaceLock.validateLocked(); if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); } finally { @@ -169,36 +307,35 @@ public abstract class JAWTWindow implements NativeWindow { return surfaceLock.getOwner(); } - public final boolean surfaceSwap() { + public boolean surfaceSwap() { return false; } - public final void surfaceUpdated(Object updater, NativeWindow window, long when) { } - - public final long getSurfaceHandle() { + public long getSurfaceHandle() { return drawable; } - public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + + public final AWTGraphicsConfiguration getPrivateGraphicsConfiguration() { return config; } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); + } public final long getDisplayHandle() { - return config.getScreen().getDevice().getHandle(); + return getGraphicsConfiguration().getScreen().getDevice().getHandle(); } public final int getScreenIndex() { - return config.getScreen().getIndex(); - } - - public final void setSize(int width, int height) { - component.setSize(width, height); + return getGraphicsConfiguration().getScreen().getIndex(); } - public final int getWidth() { + public int getWidth() { return component.getWidth(); } - public final int getHeight() { + public int getHeight() { return component.getHeight(); } @@ -207,12 +344,8 @@ public abstract class JAWTWindow implements NativeWindow { // public synchronized void destroy() { - if(null!=component) { - if(component instanceof Window) { - ((Window)component).dispose(); - } - } - invalidate(); + invalidate(); + component = null; // don't dispose the AWT component, since we are merely an immutable uplink } public final NativeWindow getParent() { @@ -222,7 +355,7 @@ public abstract class JAWTWindow implements NativeWindow { public long getWindowHandle() { return drawable; } - + public final int getX() { return component.getX(); } @@ -230,52 +363,94 @@ public abstract class JAWTWindow implements NativeWindow { public final int getY() { return component.getY(); } - + + /** + * {@inheritDoc} + * + * <p> + * This JAWT default implementation is currently still using + * a blocking implementation. It first attempts to retrieve the location + * via a native implementation. If this fails, it tries the blocking AWT implementation. + * If the latter fails due to an external AWT tree-lock, the non block + * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used. + * The latter simply traverse up to the AWT component tree and sums the rel. position. + * We have to determine whether the latter is good enough for all cases, + * currently only OS X utilizes the non blocking method per default. + * </p> + */ public Point getLocationOnScreen(Point storage) { + Point los = getLocationOnScreenNative(storage); + if(null == los) { + if(!Thread.holdsLock(component.getTreeLock())) { + // avoid deadlock .. + if(DEBUG) { + System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this); + Thread.dumpStack(); + } + return getLocationOnScreenNonBlocking(storage, component); + } + java.awt.Point awtLOS = component.getLocationOnScreen(); + if(null!=storage) { + los = storage.translate(awtLOS.x, awtLOS.y); + } else { + los = new Point(awtLOS.x, awtLOS.y); + } + } + return los; + } + + protected Point getLocationOnScreenNative(Point storage) { int lockRes = lockSurface(); if(LOCK_SURFACE_NOT_READY == lockRes) { - // FIXME: Shall we deal with already locked or unrealized surfaces ? - System.err.println("Warning: JAWT Lock couldn't be acquired!"); - Thread.dumpStack(); + if(DEBUG) { + System.err.println("Warning: JAWT Lock couldn't be acquired: "+this); + Thread.dumpStack(); + } return null; } try { - Point d = getLocationOnScreenImpl(0, 0); + Point d = getLocationOnScreenNativeImpl(0, 0); if(null!=d) { if(null!=storage) { storage.translate(d.getX(),d.getY()); return storage; } - return d; - } - // fall through intended .. - if(!Thread.holdsLock(component.getTreeLock())) { - // FIXME: Verify if this check is still required! - System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock!"); - Thread.dumpStack(); - return null; // avoid deadlock .. } - java.awt.Point awtLOS = component.getLocationOnScreen(); - int dx = (int) ( awtLOS.getX() + .5 ) ; - int dy = (int) ( awtLOS.getY() + .5 ) ; - if(null!=storage) { - return storage.translate(dx, dy); - } - return new Point(dx, dy); + return d; } finally { unlockSurface(); + } + } + protected abstract Point getLocationOnScreenNativeImpl(int x, int y); + + protected static Point getLocationOnScreenNonBlocking(Point storage, Component comp) { + int x = 0; + int y = 0; + while(null != comp) { + x += comp.getX(); + y += comp.getY(); + comp = comp.getParent(); } + if(null!=storage) { + storage.translate(x, y); + return storage; + } + return new Point(x, y); } - protected abstract Point getLocationOnScreenImpl(int x, int y); - - @Override + + public boolean hasFocus() { + return component.hasFocus(); + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("JAWT-Window["+ "windowHandle 0x"+Long.toHexString(getWindowHandle())+ ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", bounds "+bounds); + ", bounds "+bounds+", insets "+insets+ + ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface); if(null!=component) { sb.append(", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ ", visible "+component.isVisible()); @@ -283,8 +458,9 @@ public abstract class JAWTWindow implements NativeWindow { sb.append(", component NULL"); } sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ - ",\n\tconfig "+config+ - ",\n\tawtComponent "+getAWTComponent()+"]"); + ",\n\tconfig "+getPrivateGraphicsConfiguration()+ + ",\n\tawtComponent "+getAWTComponent()+ + ",\n\tsurfaceLock "+surfaceLock+"]"); return sb.toString(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index d4f6a95d4..ab2986fbe 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -40,38 +40,94 @@ 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.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.SurfaceChangeable; import javax.media.nativewindow.util.Point; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -// import jogamp.nativewindow.macosx.OSXUtil; - -public class MacOSXJAWTWindow extends JAWTWindow { +import jogamp.nativewindow.macosx.OSXUtil; +public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable { public MacOSXJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { super(comp, config); + if(DEBUG) { + dumpInfo(); + } } - protected void validateNative() throws NativeWindowException { + protected void invalidateNative() { + surfaceHandle=0; + if(isOffscreenLayerSurfaceEnabled()) { + if(0 != drawable) { + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + } + } } + protected void attachSurfaceLayerImpl(final long layerHandle) { + OSXUtil.AddCASublayer(rootSurfaceLayerHandle, layerHandle); + } + + protected void detachSurfaceLayerImpl(final long layerHandle) { + OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle); + } + + public long getSurfaceHandle() { + return isOffscreenLayerSurfaceEnabled() ? surfaceHandle : super.getSurfaceHandle() ; + } + + public void setSurfaceHandle(long surfaceHandle) { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new java.lang.UnsupportedOperationException("Not using CALAYER"); + } + if(DEBUG) { + System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + } + sscSet &= 0 != surfaceHandle; // reset ssc flag if NULL surfaceHandle, ie. back to JAWT + this.surfaceHandle = surfaceHandle; + } + + public void surfaceSizeChanged(int width, int height) { + sscSet = true; + sscWidth = width; + sscHeight = height; + } + + public int getWidth() { + return sscSet ? sscWidth : super.getWidth(); + } + + public int getHeight() { + return sscSet ? sscHeight: super.getHeight(); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + // use offscreen if supported and [ applet or requested ] + return JAWTUtil.getJAWT(getShallUseOffscreenLayer() || isApplet()); + } protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + 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 res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; @@ -87,37 +143,86 @@ public class MacOSXJAWTWindow extends JAWTWindow { if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { ret = NativeWindow.LOCK_SURFACE_CHANGED; } - if (firstLock) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - dsi = ds.GetDrawingSurfaceInfo(); - return null; - } - }); - } else { - dsi = ds.GetDrawingSurfaceInfo(); + 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 (dsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + updateBounds(dsi.getBounds()); + if (DEBUG && firstLock ) { + dumpInfo(); } firstLock = false; - macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(); - if (macosxdsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } - drawable = macosxdsi.getCocoaViewRef(); - - if (drawable == 0) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + if( !isOffscreenLayerSurfaceEnabled() ) { + macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(getJAWT()); + if (macosxdsi == null) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } + drawable = macosxdsi.getCocoaViewRef(); + + if (drawable == 0) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } else { + ret = NativeWindow.LOCK_SUCCESS; + } } else { - updateBounds(dsi.getBounds()); + /** + * 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. + */ + if(0 == drawable) { + drawable = OSXUtil.CreateNSWindow(0, 0, getBounds().getWidth(), getBounds().getHeight()); + if(0 == drawable) { + unlockSurfaceImpl(); + throw new NativeWindowException("Unable to created dummy NSWindow (layered case)"); + } + // fix caps reflecting offscreen! + Capabilities caps = (Capabilities) getPrivateGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + getPrivateGraphicsConfiguration().setChosenCapabilities(caps); + caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); + } + if(0 == rootSurfaceLayerHandle) { + rootSurfaceLayerHandle = OSXUtil.CreateCALayer(); + if(0 == rootSurfaceLayerHandle) { + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException("Could not create root CALayer: "+this); + } + if(!AttachJAWTSurfaceLayer(dsi, rootSurfaceLayerHandle)) { + OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); + rootSurfaceLayerHandle = 0; + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException("Could not attach JAWT surfaceLayerHandle: "+this); + } + } + ret = NativeWindow.LOCK_SUCCESS; } + return ret; } - + protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -126,30 +231,65 @@ public class MacOSXJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; - macosxdsi = null; } - protected Point getLocationOnScreenImpl(int x, int y) { - Component c = component; - while(null != c) { - x += c.getX(); - y += c.getY(); - c = c.getParent(); + private void dumpInfo() { + System.err.println("MaxOSXJAWTWindow: 0x"+Integer.toHexString(this.hashCode())+" - thread: "+Thread.currentThread().getName()); + if(null != getJAWT()) { + System.err.println("JAWT version: 0x"+Integer.toHexString(getJAWT().getCachedVersion())+ + ", CA_LAYER: "+ JAWTUtil.isJAWTUsingOffscreenLayer(getJAWT())+ + ", isLayeredSurface "+isOffscreenLayerSurfaceEnabled()+", bounds "+bounds+", insets "+insets); + } else { + System.err.println("JAWT n/a, bounds "+bounds+", insets "+insets); } - // return OSXUtil.GetLocationOnScreen(getWindowHandle(), x, y); - return new Point(x, y); + // Thread.dumpStack(); } + + /** + * {@inheritDoc} + * <p> + * On OS X locking the surface at this point (ie after creation and for location validation) + * is 'tricky' since the JVM traverses through many threads and crashes at: + * lockSurfaceImpl() { + * .. + * ds = getJAWT().GetDrawingSurface(component); + * due to a SIGSEGV. + * + * Hence we have some threading / sync issues with the native JAWT implementation. + * </p> + */ + @Override + public Point getLocationOnScreen(Point storage) { + return getLocationOnScreenNonBlocking(storage, component); + } + protected Point getLocationOnScreenNativeImpl(final int x0, final int y0) { return null; } + private static boolean AttachJAWTSurfaceLayer(JAWT_DrawingSurfaceInfo dsi, long caLayer) { + if(0==caLayer) { + throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); + } + return AttachJAWTSurfaceLayer0(dsi.getBuffer(), caLayer); + } + + private static native boolean AttachJAWTSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; + private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; - + + private long rootSurfaceLayerHandle = 0; // is autoreleased, once it is attached to the JAWT_SurfaceLayer + + private long surfaceHandle = 0; + private int sscWidth, sscHeight; + private boolean sscSet = 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 5ad22807f..bf5c18eaf 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java @@ -95,7 +95,7 @@ public class Win32SunJDKReflection { public static int graphicsConfigurationGetPixelFormatID(AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { - return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getGraphicsConfiguration()); + return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; } catch (Exception e) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 982b94888..786682b17 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -47,10 +47,11 @@ import javax.media.nativewindow.util.Point; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; public class WindowsJAWTWindow extends JAWTWindow { @@ -58,18 +59,24 @@ public class WindowsJAWTWindow extends JAWTWindow { super(comp, config); } - protected void validateNative() throws NativeWindowException { - } - - @Override - protected synchronized void invalidate() { - super.invalidate(); + 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"); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + return JAWTUtil.getJAWT(false); // no offscreen + } + protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); + ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); @@ -94,7 +101,8 @@ public class WindowsJAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(); + updateBounds(dsi.getBounds()); + win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (win32dsi == null) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; @@ -104,14 +112,12 @@ public class WindowsJAWTWindow extends JAWTWindow { if (windowHandle == 0 || drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } protected void unlockSurfaceImpl() throws NativeWindowException { - long startTime = 0; + drawable = 0; // invalid HDC if(null!=ds) { if (null!=dsi) { ds.FreeDrawingSurfaceInfo(dsi); @@ -119,7 +125,7 @@ public class WindowsJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; @@ -131,8 +137,8 @@ public class WindowsJAWTWindow extends JAWTWindow { return windowHandle; } - protected Point getLocationOnScreenImpl(int x, int y) { - return GDI.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); + protected Point getLocationOnScreenNativeImpl(int x, int y) { + return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java index 5d4fa0dad..743d371b7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java @@ -28,9 +28,13 @@ package jogamp.nativewindow.jawt.x11; import jogamp.nativewindow.jawt.*; +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; 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)}. @@ -41,20 +45,32 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11JAWTToolkitLock implements ToolkitLock { long displayHandle; + RecursiveLock lock; public X11JAWTToolkitLock(long displayHandle) { this.displayHandle = displayHandle; + if(!X11Util.isNativeLockAvailable()) { + lock = LockFactory.createRecursiveLock(); + } } public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock()"); } + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } JAWTUtil.lockToolkit(); - X11Util.XLockDisplay(displayHandle); + if(null == lock) { + X11Lib.XLockDisplay(displayHandle); + } else { + lock.lock(); + } } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock()"); } - X11Util.XUnlockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XUnlockDisplay(displayHandle); + } else { + lock.unlock(); + } JAWTUtil.unlockToolkit(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 2319d6269..35dc2343f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -38,20 +38,17 @@ package jogamp.nativewindow.jawt.x11; import javax.media.nativewindow.AbstractGraphicsConfiguration; -import javax.media.nativewindow.AbstractGraphicsDevice; -import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; -import javax.media.nativewindow.awt.AWTGraphicsDevice; import javax.media.nativewindow.util.Point; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -import jogamp.nativewindow.x11.X11Util; +import jogamp.nativewindow.x11.X11Lib; public class X11JAWTWindow extends JAWTWindow { @@ -59,36 +56,22 @@ public class X11JAWTWindow extends JAWTWindow { super(comp, config); } - protected void validateNative() throws NativeWindowException { - AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); + protected void invalidateNative() { } - if(awtDevice.getHandle() != 0) { - // subtype and handle set already, done - return; - } - - long displayHandle = 0; - - // first try a pre-existing attached native configuration, ie native X11GraphicsDevice - AbstractGraphicsConfiguration aconfig = (null!=config) ? config.getNativeGraphicsConfiguration() : null; - AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; - AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; // X11GraphicsDevice - if(null!=adevice) { - displayHandle = adevice.getHandle(); - } - - if(0 == displayHandle) { - displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(awtDevice.getGraphicsDevice()); - } - if(0==displayHandle) { - throw new InternalError("X11JAWTWindow: No X11 Display handle available"); - } - awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); + 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"); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + return JAWTUtil.getJAWT(false); // no offscreen + } + protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); + ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); @@ -113,7 +96,8 @@ public class X11JAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); + updateBounds(dsi.getBounds()); + x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (x11dsi == null) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; @@ -122,8 +106,6 @@ public class X11JAWTWindow extends JAWTWindow { if (drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } @@ -136,15 +118,15 @@ public class X11JAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; x11dsi = null; } - protected Point getLocationOnScreenImpl(int x, int y) { - return X11Util.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + protected Point getLocationOnScreenNativeImpl(int x, int y) { + return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java index b576b0c6b..08d471448 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java @@ -55,14 +55,14 @@ import javax.media.nativewindow.awt.AWTGraphicsConfiguration; the purposes of correctly enumerating the available visuals. */ public class X11SunJDKReflection { - private static Class x11GraphicsDeviceClass; - private static Method x11GraphicsDeviceGetDisplayMethod; - private static Class x11GraphicsConfigClass; - private static Method x11GraphicsConfigGetVisualMethod; - private static boolean initted; + private static Class<?> x11GraphicsDeviceClass; + private static Method x11GraphicsDeviceGetDisplayMethod; + private static Class<?> x11GraphicsConfigClass; + private static Method x11GraphicsConfigGetVisualMethod; + private static boolean initialized; static { - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { try { x11GraphicsDeviceClass = Class.forName("sun.awt.X11GraphicsDevice"); @@ -72,7 +72,7 @@ public class X11SunJDKReflection { x11GraphicsConfigClass = Class.forName("sun.awt.X11GraphicsConfig"); x11GraphicsConfigGetVisualMethod = x11GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); x11GraphicsConfigGetVisualMethod.setAccessible(true); - initted = true; + initialized = true; } catch (Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } @@ -82,7 +82,7 @@ public class X11SunJDKReflection { } public static long graphicsDeviceGetDisplay(GraphicsDevice device) { - if (!initted) { + if (!initialized) { return 0; } @@ -96,7 +96,7 @@ public class X11SunJDKReflection { public static int graphicsConfigurationGetVisualID(AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { - return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getGraphicsConfiguration()); + return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; } catch (Exception e) { @@ -105,7 +105,7 @@ public class X11SunJDKReflection { } public static int graphicsConfigurationGetVisualID(GraphicsConfiguration config) { - if (!initted) { + if (!initialized) { return 0; } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index cd558c05d..5b1e4b0a7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -1,3 +1,30 @@ +/** + * 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. + */ package jogamp.nativewindow.macosx; import javax.media.nativewindow.NativeWindowException; @@ -34,6 +61,42 @@ public class OSXUtil { return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); } + public static long CreateNSView(int x, int y, int width, int height) { + return CreateNSView0(x, y, width, height); + } + public static void DestroyNSView(long nsView) { + DestroyNSView0(nsView); + } + + public static long CreateNSWindow(int x, int y, int width, int height) { + return CreateNSWindow0(x, y, width, height); + } + public static void DestroyNSWindow(long nsWindow) { + DestroyNSWindow0(nsWindow); + } + + public static long CreateCALayer() { + return CreateCALayer0(); + } + public static void AddCASublayer(long rootCALayer, long subCALayer) { + if(0==rootCALayer || 0==subCALayer) { + throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); + } + AddCASublayer0(rootCALayer, subCALayer); + } + public static void RemoveCASublayer(long rootCALayer, long subCALayer) { + if(0==rootCALayer || 0==subCALayer) { + throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); + } + RemoveCASublayer0(rootCALayer, subCALayer); + } + public static void DestroyCALayer(long caLayer) { + if(0==caLayer) { + throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); + } + DestroyCALayer0(caLayer); + } + public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) { if(IsMainThread0()) { runnable.run(); // don't leave the JVM @@ -48,6 +111,14 @@ public class OSXUtil { private static native boolean initIDs0(); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); + private static native long CreateNSView0(int x, int y, int width, int height); + private static native void DestroyNSView0(long nsView); + private static native long CreateNSWindow0(int x, int y, int width, int height); + private static native void DestroyNSWindow0(long nsWindow); + private static native long CreateCALayer0(); + private static native void AddCASublayer0(long rootCALayer, long subCALayer); + 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 boolean IsMainThread0(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java index 1ad909897..aab1556da 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java @@ -202,7 +202,9 @@ public class SWTAccessor { 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); + // FIXME: May think about creating a private non-shared X11 Display handle, like we use to for AWT + // to avoid locking problems ! + return new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, false); } if( NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false) ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java index 68cf8af45..c8ed8e070 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java @@ -61,14 +61,22 @@ public class GDISurface extends ProxySurface { throw new InternalError("surface not released"); } surfaceHandle = GDI.GetDC(windowHandle); + /* + if(0 == surfaceHandle) { + System.err.println("****** DC Acquire: 0x"+Long.toHexString(windowHandle)+", isWindow "+GDI.IsWindow(windowHandle)+", isVisible "+GDI.IsWindowVisible(windowHandle)+", GDI LastError: "+GDI.GetLastError()+", 0x"+Long.toHexString(surfaceHandle)+", GDI LastError: "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); + Thread.dumpStack(); + } + */ return (0 != surfaceHandle) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; } protected void unlockSurfaceImpl() { if (0 == surfaceHandle) { - throw new InternalError("surface not acquired"); + throw new InternalError("surface not acquired: "+this+", thread: "+Thread.currentThread().getName()); + } + if(0 == GDI.ReleaseDC(windowHandle, surfaceHandle)) { + throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); } - GDI.ReleaseDC(windowHandle, surfaceHandle); surfaceHandle=0; } @@ -77,11 +85,12 @@ public class GDISurface extends ProxySurface { } public String toString() { - return "GDISurface[config "+config+ + return "GDISurface[config "+getPrivateGraphicsConfiguration()+ ", displayHandle 0x"+Long.toHexString(getDisplayHandle())+ ", windowHandle 0x"+Long.toHexString(windowHandle)+ ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", size "+getWidth()+"x"+getHeight()+"]"; + ", size "+getWidth()+"x"+getHeight()+ + ", surfaceLock "+surfaceLock+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java new file mode 100644 index 000000000..be531d9ee --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -0,0 +1,101 @@ +/** + * 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. + */ +package jogamp.nativewindow.windows; + +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.NativeWindowException; + +import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.x11.X11Util; + +public class GDIUtil { + private static final boolean DEBUG = Debug.debug("GDIUtil"); + + private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ; + private static RegisteredClassFactory dummyWindowClassFactory; + private static boolean isInit = false; + + public static synchronized void initSingleton(boolean firstX11ActionOnProcess) { + if(!isInit) { + synchronized(X11Util.class) { + if(!isInit) { + isInit = true; + NWJNILibLoader.loadNativeWindow("win32"); + + if( !initIDs0() ) { + throw new NativeWindowException("GDI: Could not initialized native stub"); + } + + if(DEBUG) { + System.out.println("GDI.isFirstX11ActionOnProcess: "+firstX11ActionOnProcess); + } + + dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0()); + } + } + } + } + + public static boolean requiresToolkitLock() { 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) { + synchronized(dummyWindowSync) { + dummyWindowClass = dummyWindowClassFactory.getSharedClass(); + return CreateDummyWindow0(dummyWindowClass.getHandle(), dummyWindowClass.getName(), dummyWindowClass.getName(), x, y, width, height); + } + } + + public static boolean DestroyDummyWindow(long hwnd) { + boolean res; + synchronized(dummyWindowSync) { + if( null == dummyWindowClass ) { + throw new InternalError("GDI Error ("+dummyWindowClassFactory.getSharedRefCount()+"): SharedClass is null"); + } + res = GDI.DestroyWindow(hwnd); + dummyWindowClassFactory.releaseSharedClass(); + } + return res; + } + + public static Point GetRelativeLocation(long src_win, long dest_win, int src_x, 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); + + private static native boolean initIDs0(); + 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); +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java index 15e0a67cb..00bedfc8e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java @@ -34,34 +34,44 @@ import javax.media.nativewindow.NativeWindowException; public class RegisteredClassFactory { static final boolean DEBUG = Debug.debug("RegisteredClass"); - private static ArrayList sharedClasses = new ArrayList(); + private static ArrayList<RegisteredClassFactory> registeredFactories = new ArrayList<RegisteredClassFactory>(); + private String classBaseName; - long wndProc; + private long wndProc; private RegisteredClass sharedClass = null; private int classIter = 0; private int sharedRefCount = 0; - private Object sync = new Object(); + private final Object sync = new Object(); /** - * Intended for a JVM shutdown hook, hence little synchronization + * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. */ public static void shutdownSharedClasses() { - synchronized(sharedClasses) { - for(int i=0; i<sharedClasses.size(); i++) { - RegisteredClass sc = (RegisteredClass) sharedClasses.get(i); - GDI.DestroyWindowClass(sc.getHandle(), sc.getName()); - if(DEBUG) { - System.err.println("RegisteredClassFactory shutdownSharedClasses "+i+"/"+sharedClasses.size()+": "+sc); + synchronized(registeredFactories) { + 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()); + rcf.sharedClass = null; + rcf.sharedRefCount = 0; + rcf.classIter = 0; + if(DEBUG) { + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+" shutdownSharedClasses : "+rcf.sharedClass); + } + } } } - sharedClasses.clear(); } } public RegisteredClassFactory(String classBaseName, long wndProc) { this.classBaseName = classBaseName; this.wndProc = wndProc; + synchronized(registeredFactories) { + registeredFactories.add(this); + } } public RegisteredClass getSharedClass() throws NativeWindowException { @@ -76,19 +86,17 @@ public class RegisteredClassFactory { } String clazzName = null; boolean registered = false; - while ( !registered && Integer.MAX_VALUE >= classIter ) { + 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 = GDI.CreateWindowClass(hInstance, clazzName, wndProc); + registered = GDIUtil.CreateWindowClass(hInstance, clazzName, wndProc); } if( !registered ) { throw new NativeWindowException("Error: Could not create WindowClass: "+clazzName); } sharedClass = new RegisteredClass(hInstance, clazzName); - synchronized(sharedClasses) { - sharedClasses.add(sharedClass); - } if(DEBUG) { System.err.println("RegisteredClassFactory getSharedClass ("+sharedRefCount+") initialized: "+sharedClass); } @@ -113,10 +121,7 @@ public class RegisteredClassFactory { throw new InternalError("Error ("+sharedRefCount+"): SharedClass is null"); } if( 0 == sharedRefCount ) { - GDI.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); - synchronized(sharedClasses) { - sharedClasses.remove(sharedClass); - } + GDIUtil.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); if(DEBUG) { System.err.println("RegisteredClassFactory releaseSharedClass ("+sharedRefCount+") released: "+sharedClass); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index b669bce75..268416266 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -33,10 +33,22 @@ package jogamp.nativewindow.x11; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, new X11GraphicsConfigurationFactory()); + } + private X11GraphicsConfigurationFactory() { + } + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) throws IllegalArgumentException, NativeWindowException { @@ -55,7 +67,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor int num[] = { -1 }; long display = screen.getDevice().getHandle(); - XVisualInfo[] xvis = X11Util.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); + XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); if(xvis==null || num[0]<1) { return null; @@ -81,7 +93,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor vinfo_template.setC_class(c_class); long display = screen.getDevice().getHandle(); - XVisualInfo[] vinfos = X11Util.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); + XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); XVisualInfo best=null; int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); for (int i = 0; vinfos!=null && i < num[0]; i++) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java index fb0aff10d..5166ef577 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java @@ -29,6 +29,9 @@ package jogamp.nativewindow.x11; 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 {@link X11Util#XLockDisplay(long)}. @@ -38,18 +41,30 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11ToolkitLock implements ToolkitLock { long displayHandle; + RecursiveLock lock; public X11ToolkitLock(long displayHandle) { this.displayHandle = displayHandle; + if(!X11Util.isNativeLockAvailable()) { + lock = LockFactory.createRecursiveLock(); + } } public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock()"); } - X11Util.XLockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XLockDisplay(displayHandle); + } else { + lock.lock(); + } } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock()"); } - X11Util.XUnlockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XUnlockDisplay(displayHandle); + } else { + lock.unlock(); + } } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 5c1839250..560130dd1 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -33,19 +33,18 @@ package jogamp.nativewindow.x11; -import com.jogamp.common.util.LongObjectHashMap; -import jogamp.nativewindow.Debug; -import jogamp.nativewindow.NWJNILibLoader; - -import javax.media.nativewindow.*; - -import java.nio.Buffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; import java.security.AccessController; import java.util.ArrayList; import java.util.List; -import javax.media.nativewindow.util.Point; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NWJNILibLoader; + +import com.jogamp.common.util.LongObjectHashMap; /** * Contains a thread safe X11 utility to retrieve display connections. @@ -53,54 +52,88 @@ import javax.media.nativewindow.util.Point; public class X11Util { /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 - * - * It is observed that ATI X11 drivers, eg. fglrx 8.78.6 and fglrx 11.08/8.881, + * <p> + * It is observed that ATI X11 drivers, eg. + * <ul> + * <li>fglrx 8.78.6,</li> + * <li>fglrx 11.08/8.881 and </li> + * <li>fglrx 11.11/8.911</li> + * </ul> * are quite sensitive to multiple Display connections. - * Here, closing displays shall happen in the same order as - * they were opened, -OR- shall not be closed at all! - * Otherwise some driver related bug appears and brings down the JVM. + * </p> + * <p> + * With the above drivers closing displays shall happen in the same order as + * they were opened, <b>or</b> shall not be closed at all! + * If closed, some driver related bug appears and brings down the JVM. + * </p> + * <p> * You may test this, ie just reverse the destroy order below. * See also native test: jogl/test/native/displayMultiple02.c - * - * Our current 'workaround' is to not close them at all if driver vendor is ATI. + * </p> + * <p> + * Workaround is to not close them at all if driver vendor is ATI. + * </p> */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = true; - - public static final boolean XINITTHREADS_ALWAYS_ENABLED = 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; + private static final boolean DEBUG = Debug.debug("X11Util"); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.getBooleanProperty("nativewindow.debug.X11Util.TraceDisplayLifecycle", true, AccessController.getContext()); - private static volatile String nullDisplayName = null; - private static boolean requiresX11Lock = false; - private static boolean isInit = false; + 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 int setX11ErrorHandlerRecCount = 0; private static Object setX11ErrorHandlerLock = new Object(); - public static synchronized void initSingleton(final boolean firstX11ActionOnProcess) { + @SuppressWarnings("unused") + public static void initSingleton(final boolean firstX11ActionOnProcess) { if(!isInit) { - NWJNILibLoader.loadNativeWindow("x11"); - - /** - * Always issue XInitThreads() since we have independent - * off-thread created Display connections able to utilize multithreading, - * ie NEWT (jogamp.newt.x11.X11Display.createNativeImpl()) !! - */ - initialize0( XINITTHREADS_ALWAYS_ENABLED ? true : firstX11ActionOnProcess ); - - requiresX11Lock = !firstX11ActionOnProcess ; - - if(DEBUG) { - System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+ - ", XINITTHREADS_ALWAYS_ENABLED "+XINITTHREADS_ALWAYS_ENABLED+ - ", requiresX11Lock "+requiresX11Lock); + synchronized(X11Util.class) { + if(!isInit) { + isInit = true; + NWJNILibLoader.loadNativeWindow("x11"); + + final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess; + final boolean isXInitThreadsOK = initialize0( XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess ); + isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; + + final long dpy = X11Lib.XOpenDisplay(null); + try { + nullDisplayName = X11Lib.XDisplayString(dpy); + } finally { + X11Lib.XCloseDisplay(dpy); + } + + if(DEBUG) { + System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+ + ", requiresX11Lock "+requiresX11Lock+ + ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ + ", isX11LockAvailable "+isX11LockAvailable+ + ", X11 Display(NULL) <"+nullDisplayName+">"); + // Thread.dumpStack(); + } + } } - isInit = true; } } + + public static synchronized boolean isNativeLockAvailable() { + return isX11LockAvailable; + } + + public static synchronized boolean requiresToolkitLock() { + return requiresX11Lock; + } public static void setX11ErrorHandler(boolean onoff, boolean quiet) { synchronized(setX11ErrorHandlerLock) { @@ -121,42 +154,7 @@ public class X11Util { } } - public static boolean requiresToolkitLock() { - return requiresX11Lock; - } - - public static void lockDefaultToolkit(long dpyHandle) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - if(requiresX11Lock) { - X11Util.XLockDisplay(dpyHandle); - } - } - - public static void unlockDefaultToolkit(long dpyHandle) { - if(requiresX11Lock) { - X11Util.XUnlockDisplay(dpyHandle); - } - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - public static String getNullDisplayName() { - if(null==nullDisplayName) { // volatile: ok - synchronized(X11Util.class) { - if(null==nullDisplayName) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - long dpy = X11Lib.XOpenDisplay(null); - try { - nullDisplayName = X11Lib.XDisplayString(dpy); - } finally { - X11Lib.XCloseDisplay(dpy); - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - if(DEBUG) { - System.out.println("X11 Display(NULL) <"+nullDisplayName+">"); - } - } - } - } return nullDisplayName; } @@ -224,7 +222,6 @@ public class X11Util { public final void setUncloseable(boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } - public final Throwable getCreationStack() { return creationStack; } @Override @@ -238,20 +235,22 @@ public class X11Util { } } - /** Returns the number of unclosed X11 Displays. + /** + * Cleanup resources. + * If <code>realXCloseOpenAndPendingDisplays</code> is <code>false</code>, + * keep alive all references (open display connection) for restart on same ClassLoader. + * + * @return number of unclosed X11 Displays.<br> * @param realXCloseOpenAndPendingDisplays if true, {@link #closePendingDisplayConnections()} is called. - */ + */ public static int shutdown(boolean realXCloseOpenAndPendingDisplays, boolean verbose) { int num=0; if(DEBUG||verbose||pendingDisplayList.size() > 0) { - String msg = "X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ - ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ - ", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")" ; + System.err.println("X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ + ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ + ", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")"); if(DEBUG) { - Exception e = new Exception(msg); - e.printStackTrace(); - } else { - System.err.println(msg); + Thread.dumpStack(); } if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); @@ -264,10 +263,11 @@ public class X11Util { synchronized(globalLock) { if(realXCloseOpenAndPendingDisplays) { closePendingDisplayConnections(); + openDisplayList.clear(); + pendingDisplayList.clear(); + openDisplayMap.clear(); + shutdown0(); } - openDisplayList.clear(); - pendingDisplayList.clear(); - openDisplayMap.clear(); } return num; } @@ -304,9 +304,9 @@ public class X11Util { public static void dumpOpenDisplayConnections() { synchronized(globalLock) { System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size()); - for(int i=0; i<pendingDisplayList.size(); i++) { + for(int i=0; i<openDisplayList.size(); i++) { NamedDisplay ndpy = openDisplayList.get(i); - System.err.println("X11Util: ["+i+"]: "+ndpy); + System.err.println("X11Util: Open["+i+"]: "+ndpy); if(null!=ndpy) { Throwable t = ndpy.getCreationStack(); if(null!=t) { @@ -316,7 +316,7 @@ public class X11Util { } } } - + public static int getPendingDisplayConnectionNumber() { synchronized(globalLock) { return pendingDisplayList.size(); @@ -328,7 +328,7 @@ public class X11Util { System.err.println("X11Util: Pending X11 Display Connections: "+pendingDisplayList.size()); for(int i=0; i<pendingDisplayList.size(); i++) { NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); - System.err.println("X11Util: ["+i+"]: "+ndpy); + System.err.println("X11Util: Pending["+i+"]: "+ndpy); if(null!=ndpy) { Throwable t = ndpy.getCreationStack(); if(null!=t) { @@ -384,8 +384,8 @@ public class X11Util { } } if(DEBUG) { - Exception e = new Exception("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); - e.printStackTrace(); + System.err.println("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); + // Thread.dumpStack(); } return namedDpy.getHandle(); } @@ -408,10 +408,6 @@ public class X11Util { if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } if(!namedDpy.isUncloseable()) { - if(DEBUG) { - System.err.println("X11Util.Display: XCloseDisplay "+namedDpy+". Thread "+Thread.currentThread().getName()); - Thread.dumpStack(); - } XCloseDisplay(namedDpy.getHandle()); } else { // for reuse @@ -439,7 +435,7 @@ public class X11Util { public static String validateDisplayName(String name, long handle) { if( ( null==name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) && 0!=handle) { - name = XDisplayString(handle); + name = X11Lib.XDisplayString(handle); } return validateDisplayName(name); } @@ -455,8 +451,8 @@ public class X11Util { try { long handle = X11Lib.XOpenDisplay(arg0); if(TRACE_DISPLAY_LIFECYCLE) { - Throwable t = new Throwable(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - t.printStackTrace(); + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); } return handle; } finally { @@ -468,8 +464,8 @@ public class X11Util { NativeWindowFactory.getDefaultToolkitLock().lock(); try { if(TRACE_DISPLAY_LIFECYCLE) { - Throwable t = new Throwable(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - t.printStackTrace(); + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); } int res = -1; X11Util.setX11ErrorHandler(true, DEBUG ? false : true); @@ -487,209 +483,7 @@ public class X11Util { } } - public static int XFree(Buffer arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - return X11Lib.XFree(arg0); - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - } - - public static int XSync(long display, boolean discard) { - lockDefaultToolkit(display); - try { - return X11Lib.XSync(display, discard); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void XSynchronize(long display, boolean onoff) { - lockDefaultToolkit(display); - try { - X11Lib.XSynchronize(display, onoff); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XineramaEnabled(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XineramaEnabled(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int DefaultScreen(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.DefaultScreen(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long RootWindow(long display, int screen_number) { - lockDefaultToolkit(display); - try { - return X11Lib.RootWindow(display, screen_number); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long XCreatePixmap(long display, long arg1, int arg2, int arg3, int arg4) { - lockDefaultToolkit(display); - try { - return X11Lib.XCreatePixmap(display, arg1, arg2, arg3, arg4); - } finally { - unlockDefaultToolkit(display); - } - } - - public static String XDisplayString(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XDisplayString(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int XFlush(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XFlush(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int XFreePixmap(long display, long arg1) { - lockDefaultToolkit(display); - try { - return X11Lib.XFreePixmap(display, arg1); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long DefaultVisualID(long display, int screen) { - lockDefaultToolkit(display); - try { - return X11Lib.DefaultVisualID(display, screen); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long CreateDummyWindow(long display, int screen_index, long visualID, int width, int height) { - lockDefaultToolkit(display); - try { - return X11Lib.CreateDummyWindow(display, screen_index, visualID, width, height); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void DestroyDummyWindow(long display, long window) { - lockDefaultToolkit(display); - try { - X11Lib.DestroyDummyWindow(display, window); - } finally { - unlockDefaultToolkit(display); - } - } - - public static Point GetRelativeLocation(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y) { - lockDefaultToolkit(display); - try { - return X11Lib.GetRelativeLocation(display, screen_index, src_win, dest_win, src_x, src_y); - } finally { - unlockDefaultToolkit(display); - } - } - - public static XVisualInfo[] XGetVisualInfo(long display, long arg1, XVisualInfo arg2, int[] arg3, int arg3_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XGetVisualInfo(display, arg1, arg2, arg3, arg3_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, green_array, blue_array); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, short[] red_array, int red_array_offset, short[] green_array, int green_array_offset, short[] blue_array, int blue_array_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRampSize(long display, int screen, IntBuffer size) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRampSize(long display, int screen, int[] size, int size_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size, size_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, green_array, blue_array); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, short[] red_array, int red_array_offset, short[] green_array, int green_array_offset, short[] blue_array, int blue_array_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void XLockDisplay(long handle) { - if(ToolkitLock.TRACE_LOCK) { - System.out.println("+++ X11 Display Lock get 0x"+Long.toHexString(handle)); - } - X11Lib.XLockDisplay(handle); - } - - public static void XUnlockDisplay(long handle) { - if(ToolkitLock.TRACE_LOCK) { - System.out.println("--- X11 Display Lock rel 0x"+Long.toHexString(handle)); - } - X11Lib.XUnlockDisplay(handle); - } - - private static native void initialize0(boolean firstUIActionOnProcess); + private static native boolean initialize0(boolean firstUIActionOnProcess); + 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 new file mode 100644 index 000000000..efaf4728c --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -0,0 +1,185 @@ +/* + * 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 + * 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. + */ + +package jogamp.nativewindow.x11.awt; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ToolkitLock; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; +import javax.media.nativewindow.awt.AWTGraphicsDevice; +import javax.media.nativewindow.awt.AWTGraphicsScreen; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsDevice; +import javax.media.nativewindow.x11.X11GraphicsScreen; + +import jogamp.nativewindow.jawt.x11.X11SunJDKReflection; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; + +public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory { + + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, new X11AWTGraphicsConfigurationFactory()); + } + private X11AWTGraphicsConfigurationFactory() { + } + + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + if (absScreen != null && + !(absScreen instanceof AWTGraphicsScreen)) { + throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects"); + } + if(null==absScreen) { + absScreen = AWTGraphicsScreen.createDefault(); + } + + return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen); + } + + public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic( + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen) { + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen); + } + + final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); + + long displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(device); + boolean owner = false; + if(0==displayHandle) { + displayHandle = X11Util.openDisplay(null); + owner = true; + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - X11AWTGraphicsConfigurationFactory: create local X11 display"); + } + } else { + /** + * Using the AWT display handle works fine with NVidia. + * 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(displayHandle); + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - X11AWTGraphicsConfigurationFactory: create X11 display @ "+displayName+" / 0x"+Long.toHexString(displayHandle)); + } + displayHandle = X11Util.openDisplay(displayName); + owner = true; + } + 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); + final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen); + } + + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device); + X11GraphicsConfiguration x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + if (x11Config == null) { + throw new NativeWindowException("Unable to choose a GraphicsConfiguration (1): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); + } + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: chosen x11Config: "+x11Config); + } + + // + // Match the X11/GL Visual with AWT: + // - choose a config AWT agnostic and then + // - try to find the visual within the GraphicsConfiguration + // + // 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(); + long visualID = x11Config.getVisualID(); + for (int i = 0; i < configs.length; i++) { + GraphicsConfiguration gc = configs[i]; + if (gc != null) { + if (X11SunJDKReflection.graphicsConfigurationGetVisualID(gc) == visualID) { + if(DEBUG) { + System.err.println("Found matching AWT visual: 0x"+Long.toHexString(visualID) +" -> "+x11Config); + } + return new AWTGraphicsConfiguration(awtScreen, + x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), + gc, x11Config); + } + } + } + + // try again using an AWT Colormodel compatible configuration + GraphicsConfiguration gc = device.getDefaultConfiguration(); + capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsChosen, gc); + x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + if (x11Config == null) { + throw new NativeWindowException("Unable to choose a GraphicsConfiguration (2): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); + } + visualID = x11Config.getVisualID(); + for (int i = 0; i < configs.length; i++) { + gc = configs[i]; + if (X11SunJDKReflection.graphicsConfigurationGetVisualID(gc) == visualID) { + if(DEBUG) { + System.err.println("Found matching default AWT visual: 0x"+Long.toHexString(visualID) +" -> "+x11Config); + } + return new AWTGraphicsConfiguration(awtScreen, + x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), + gc, x11Config); + } + } + + // Either we weren't able to reflectively introspect on the + // X11GraphicsConfig or something went wrong in the steps above; + // Let's take the default configuration as used on Windows and MacOSX then .. + if(DEBUG) { + System.err.println("!!! Using default configuration"); + } + + gc = device.getDefaultConfiguration(); + return new AWTGraphicsConfiguration(awtScreen, x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), gc, x11Config); + } +} + |