diff options
author | Sven Gothel <[email protected]> | 2010-10-14 21:26:43 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-10-14 21:26:43 +0200 |
commit | 774138544e1eec3330309ad682fa05154a07ab8d (patch) | |
tree | a9d612e98f1d16390763f54ab1888ff66f081a22 /src/nativewindow | |
parent | d7faeb8b96f5aba76967096006af4c420d964fef (diff) |
JOGL: Reenable Applet/Webstart/RCP support for JOGL + AWT + X11
Changed GLProfile/NativeWindowFactory/.. initialization methodology:
GLProfile:
public static synchronized void initSingleton(final boolean firstUIActionOnProcess);
NativeWindowFactory:
public static synchronized void initSingleton(final boolean firstUIActionOnProcess);
+++
Introducing NativeWindow ToolkitLock, implementations are
NullToolkitLock
JAWTToolkitLock
X11JAWTToolkitLock
X11ToolkitLock
AbstractGraphicsDevice provides generic global toolkit locking methods,
implemented by the ToolkitLock interface.
ToolkitLock's are aggregated in NativeWindow's DefaultGraphicsDevice
to implement it's superclass lock()/unlock() methods.
This enables a device specific locking strategy, ie on X11/AWT utilizing
JAWT && X11 locking, and maybe none for others (NEWT).
No locking is required for X11 / AWT, in case the above mentioned
initialization happened as a 'firstUIActionOnProcess'.
The ToolkitLock factory is currently a hardcoded part of NativeWindowFactory.
We may have to allow 3rd party NativeWindow implementations
to register custom ones.
+++
com.jogamp.opengl.impl.GLDrawableImpl cleanup:
Dealing with all locking code, providing all public methods. Exceptions are commented.
Specializations x11/windows/.. only contains platform code.
Pulled down access qualifiers if possible public -> protected.
com.jogamp.nativewindow.impl.x11.X11Util
Wrapping all X11Lib method with the new locking code.
com.jogamp.nativewindow.impl.jawt.JAWTUtil
Utilize global SunToolkit.awtLock() is available,
the fallback to global JAWT.lock().
The latter just invokes the first.
javax.media.nativewindow.awt.AWTGraphicsDevice
setHandle(long handle) -> setSubType(String type, long handle)
which also resets the ToolkitLock respecting the new type.
This ensures correct locking after the sub type has been determined,
ie AWT using an X11 peer.
+++
Misc Changes done on the way ..
GLCanvas:
Fixed inversed this.drawableHelper.isExternalAnimatorAnimating() condition,
which disabled normal repaint.
GLJPanel:
Removed drawableHelper.isExternalAnimatorAnimating() condition,
which disabled painting, since the animation thread just updates the source image.
NEWT WindowImpl:
When reparenting back to parent and 'refit' child if it's size exceeds it's parent.
More 'Fix: Memory consumption' commit 6ced17f0325d5719e992b246ffd156e5b39694b4.
NEWTEvent:
Removed code to evaluate the 'system event' attribute, need to find a better approach.
Diffstat (limited to 'src/nativewindow')
23 files changed, 1174 insertions, 313 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/GraphicsConfigurationFactoryImpl.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/GraphicsConfigurationFactoryImpl.java index 22f2d544f..96f6ab2ba 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/GraphicsConfigurationFactoryImpl.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/GraphicsConfigurationFactoryImpl.java @@ -35,9 +35,8 @@ package com.jogamp.nativewindow.impl; import javax.media.nativewindow.*; public class GraphicsConfigurationFactoryImpl extends GraphicsConfigurationFactory { - public AbstractGraphicsConfiguration chooseGraphicsConfiguration(Capabilities capabilities, - CapabilitiesChooser chooser, - AbstractGraphicsScreen screen) { + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( + Capabilities capabilities, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) { return new DefaultGraphicsConfiguration(screen, capabilities, capabilities); } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/NativeWindowFactoryImpl.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/NativeWindowFactoryImpl.java index 8f82bed2b..34f5d6267 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/NativeWindowFactoryImpl.java @@ -41,6 +41,12 @@ import javax.media.nativewindow.*; public class NativeWindowFactoryImpl extends NativeWindowFactory { protected static final boolean DEBUG = Debug.debug("NativeWindow"); + private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); + + 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 { @@ -56,7 +62,7 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { throw new IllegalArgumentException("AbstractGraphicsConfiguration is null with a non NativeWindow object"); } - if (ReflectionUtil.instanceOf(winObj, AWTComponentClassName)) { + if (NativeWindowFactory.isAWTAvailable() && ReflectionUtil.instanceOf(winObj, AWTComponentClassName)) { return getAWTNativeWindow(winObj, config); } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullToolkitLock.java new file mode 100644 index 000000000..5a03cba7f --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullToolkitLock.java @@ -0,0 +1,50 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.nativewindow.impl; + +import javax.media.nativewindow.ToolkitLock; + +/** + * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock} + * without any locking. Since there is no locking it all, + * it is intrinsically recursive. + */ +public class NullToolkitLock implements ToolkitLock { + + /** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */ + protected NullToolkitLock() { } + + public final void lock() { + if(TRACE_LOCK) { System.err.println("NullToolkitLock.lock()"); } + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/ProxySurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/ProxySurface.java index 9d9f360cd..eebcdb0ab 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/ProxySurface.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/ProxySurface.java @@ -43,10 +43,10 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.SurfaceChangeable; -import com.jogamp.common.util.RecursiveToolkitLock; +import com.jogamp.common.util.locks.RecursiveLock; public class ProxySurface implements NativeSurface, SurfaceChangeable { - private RecursiveToolkitLock recurLock = new RecursiveToolkitLock(); + private RecursiveLock recurLock = new RecursiveLock(); protected int width, height, scrnIndex; protected long surfaceHandle, displayHandle; protected AbstractGraphicsConfiguration config; @@ -78,31 +78,36 @@ public class ProxySurface implements NativeSurface, SurfaceChangeable { surfaceHandle=0; } - public synchronized int lockSurface() throws NativeWindowException { + public final int lockSurface() throws NativeWindowException { recurLock.lock(); + + if(recurLock.getRecursionCount() == 0) { + config.getScreen().getDevice().lock(); + } return LOCK_SUCCESS; } - public synchronized void unlockSurface() { + public final void unlockSurface() { + recurLock.validateLocked(); + + if(recurLock.getRecursionCount()==0) { + config.getScreen().getDevice().unlock(); + } recurLock.unlock(); } - public synchronized boolean isSurfaceLockedByOtherThread() { + public final boolean isSurfaceLockedByOtherThread() { return recurLock.isLockedByOtherThread(); } - public synchronized boolean isSurfaceLocked() { + public final boolean isSurfaceLocked() { return recurLock.isLocked(); } - public Thread getSurfaceLockOwner() { + public final Thread getSurfaceLockOwner() { return recurLock.getOwner(); } - public Exception getSurfaceLockStack() { - return recurLock.getLockedStack(); - } - public boolean surfaceSwap() { return false; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTToolkitLock.java new file mode 100644 index 000000000..017d74874 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTToolkitLock.java @@ -0,0 +1,54 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.nativewindow.impl.jawt; + +import javax.media.nativewindow.ToolkitLock; + +/** + * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock} + * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()}. + * <br> + * This strategy should only be used if AWT is using the underlying native windowing toolkit + * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call + * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets. + */ +public class JAWTToolkitLock implements ToolkitLock { + + /** Singleton via {@link JAWTUtil#getJAWTToolkitLock()} */ + protected JAWTToolkitLock() {} + + public final void lock() { + if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.lock()"); } + JAWTUtil.lockToolkit(); + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("JAWTToolkitLock.unlock()"); } + JAWTUtil.unlockToolkit(); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTUtil.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTUtil.java index 7127bacf9..ff62c9521 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTUtil.java @@ -40,27 +40,28 @@ import com.jogamp.nativewindow.impl.*; import javax.media.nativewindow.*; -import com.jogamp.common.util.RecursiveToolkitLock; +import com.jogamp.common.util.locks.RecursiveLock; import java.awt.GraphicsEnvironment; import java.lang.reflect.*; import java.security.*; public class JAWTUtil { + protected static final boolean DEBUG = Debug.debug("JAWT"); // See whether we're running in headless mode private static final boolean headlessMode; // Java2D magic .. - private static final Class j2dClazz; private static final Method isQueueFlusherThread; private static final boolean j2dExist; private static Class sunToolkitClass; private static Method sunToolkitAWTLockMethod; private static Method sunToolkitAWTUnlockMethod; - private static final boolean hasSunToolkitAWTLock; - private static final boolean useSunToolkitAWTLock; + private static boolean hasSunToolkitAWTLock; + + private static final JAWTToolkitLock jawtToolkitLock; static { JAWTJNILibLoader.loadAWTImpl(); @@ -68,45 +69,53 @@ public class JAWTUtil { headlessMode = GraphicsEnvironment.isHeadless(); - boolean ok=false; - Class jC=null; - Method m=null; - if(!headlessMode) { + boolean ok = false; + Class jC = null; + Method m = null; + if (!headlessMode) { try { jC = Class.forName("com.jogamp.opengl.impl.awt.Java2D"); m = jC.getMethod("isQueueFlusherThread", null); ok = true; - } catch (Exception e) {} + } catch (Exception e) { + } } - j2dClazz = jC; isQueueFlusherThread = m; j2dExist = ok; AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - try { - sunToolkitClass = Class.forName("sun.awt.SunToolkit"); - sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[] {}); - sunToolkitAWTLockMethod.setAccessible(true); - sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[] {}); - sunToolkitAWTUnlockMethod.setAccessible(true); - } catch (Exception e) { - // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 - } - return null; + try { + sunToolkitClass = Class.forName("sun.awt.SunToolkit"); + sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); + sunToolkitAWTLockMethod.setAccessible(true); + sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); + sunToolkitAWTUnlockMethod.setAccessible(true); + } catch (Exception e) { + // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 + } + return null; + } + }); + boolean _hasSunToolkitAWTLock = false; + if (null != sunToolkitAWTLockMethod && null != sunToolkitAWTUnlockMethod) { + try { + sunToolkitAWTLockMethod.invoke(null, null); + sunToolkitAWTUnlockMethod.invoke(null, null); + _hasSunToolkitAWTLock = true; + } catch (Exception e) { } - }); - boolean _hasSunToolkitAWTLock = false; - if ( null!=sunToolkitAWTLockMethod && null!=sunToolkitAWTUnlockMethod ) { - try { - sunToolkitAWTLockMethod.invoke(null, null); - sunToolkitAWTUnlockMethod.invoke(null, null); - _hasSunToolkitAWTLock = true; - } catch (Exception e) {} - } - hasSunToolkitAWTLock = _hasSunToolkitAWTLock; - // useSunToolkitAWTLock = hasSunToolkitAWTLock; - useSunToolkitAWTLock = false; + } + hasSunToolkitAWTLock = _hasSunToolkitAWTLock; + // hasSunToolkitAWTLock = false; + + jawtToolkitLock = new JAWTToolkitLock(); + + if (DEBUG) { + System.err.println("JAWTUtil: Has sun.awt.SunToolkit.awtLock/awtUnlock " + hasSunToolkitAWTLock); + System.err.println("JAWTUtil: Has Java2D " + j2dExist); + System.err.println("JAWTUtil: Is headless " + headlessMode); + } } public static void initSingleton() { @@ -132,8 +141,14 @@ public class JAWTUtil { return headlessMode; } - private static void awtLock() { - if(useSunToolkitAWTLock) { + /** + * Locks the AWT's global ReentrantLock.<br> + * + * JAWT's native Lock() function calls SunToolkit.awtLock(), + * which just uses AWT's global ReentrantLock.<br> + */ + public static void awtLock() { + if(hasSunToolkitAWTLock) { try { sunToolkitAWTLockMethod.invoke(null, null); } catch (Exception e) { @@ -144,8 +159,14 @@ public class JAWTUtil { } } - private static void awtUnlock() { - if(useSunToolkitAWTLock) { + /** + * Unlocks the AWT's global ReentrantLock.<br> + * + * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), + * which just uses AWT's global ReentrantLock.<br> + */ + public static void awtUnlock() { + if(hasSunToolkitAWTLock) { try { sunToolkitAWTUnlockMethod.invoke(null, null); } catch (Exception e) { @@ -156,36 +177,20 @@ public class JAWTUtil { } } - private static RecursiveToolkitLock recurLock = new RecursiveToolkitLock(); - - public static synchronized void lockToolkit() throws NativeWindowException { - recurLock.lock(); - - if(recurLock.getRecursionCount()==0 && - !isJava2DQueueFlusherThread() && - !headlessMode) { + public static void lockToolkit() throws NativeWindowException { + if(!isJava2DQueueFlusherThread() && !headlessMode) { awtLock(); } } - public static synchronized void unlockToolkit() { - recurLock.validateLocked(); - - if(recurLock.getRecursionCount()==0 && - !isJava2DQueueFlusherThread() && - !headlessMode) { + public static void unlockToolkit() { + if(!isJava2DQueueFlusherThread() && !headlessMode) { awtUnlock(); } - - recurLock.unlock(); - } - - public static boolean isToolkitLocked() { - return recurLock.isLocked(); } - public static Exception getLockedStack() { - return recurLock.getLockedStack(); + public static JAWTToolkitLock getJAWTToolkitLock() { + return jawtToolkitLock; } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java index ad0b6104b..00d64b4e4 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java @@ -38,7 +38,7 @@ package com.jogamp.nativewindow.impl.jawt; import com.jogamp.nativewindow.impl.*; -import com.jogamp.common.util.RecursiveToolkitLock; +import com.jogamp.common.util.locks.RecursiveLock; import java.awt.Component; import java.awt.Window; @@ -48,14 +48,7 @@ import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; public abstract class JAWTWindow implements NativeWindow { - protected static final boolean DEBUG = Debug.debug("JAWT"); - - // See whether we're running in headless mode - private static boolean headlessMode; - - static { - headlessMode = GraphicsEnvironment.isHeadless(); - } + protected static final boolean DEBUG = JAWTUtil.DEBUG; // lifetime: forever protected Component component; @@ -113,47 +106,60 @@ public abstract class JAWTWindow implements NativeWindow { // NativeSurface // - private RecursiveToolkitLock recurLock = new RecursiveToolkitLock(); + private RecursiveLock recurLock = new RecursiveLock(); protected abstract int lockSurfaceImpl() throws NativeWindowException; - public final synchronized int lockSurface() throws NativeWindowException { + public final int lockSurface() throws NativeWindowException { + int res = LOCK_SURFACE_NOT_READY; + recurLock.lock(); if(recurLock.getRecursionCount() == 0) { - return lockSurfaceImpl(); + config.getScreen().getDevice().lock(); + try { + res = lockSurfaceImpl(); + } finally { + // Unlock in case surface couldn't be locked + if(LOCK_SURFACE_NOT_READY >= res ) { + config.getScreen().getDevice().unlock(); + recurLock.unlock(); + } + } + } else { + res = LOCK_SUCCESS; } - return LOCK_SUCCESS; + return res; } protected abstract void unlockSurfaceImpl() throws NativeWindowException; - public synchronized void unlockSurface() { + public final void unlockSurface() { recurLock.validateLocked(); if(recurLock.getRecursionCount()==0) { - unlockSurfaceImpl(); + try { + unlockSurfaceImpl(); + } finally { + config.getScreen().getDevice().unlock(); + } } recurLock.unlock(); } - public synchronized boolean isSurfaceLockedByOtherThread() { + public final boolean isSurfaceLockedByOtherThread() { return recurLock.isLockedByOtherThread(); } - public synchronized boolean isSurfaceLocked() { + public final boolean isSurfaceLocked() { return recurLock.isLocked(); } - public Thread getSurfaceLockOwner() { + public final Thread getSurfaceLockOwner() { return recurLock.getOwner(); } - public Exception getSurfaceLockStack() { - return recurLock.getLockedStack(); - } - public boolean surfaceSwap() { return false; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTToolkitLock.java new file mode 100644 index 000000000..7eaac2ca6 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTToolkitLock.java @@ -0,0 +1,60 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.nativewindow.impl.jawt.x11; + +import com.jogamp.nativewindow.impl.jawt.*; +import com.jogamp.nativewindow.impl.x11.X11Util; +import javax.media.nativewindow.ToolkitLock; + +/** + * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} + * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. + * <br> + * This strategy should only be used if AWT is using the underlying native windowing toolkit + * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call + * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets. + */ +public class X11JAWTToolkitLock implements ToolkitLock { + long displayHandle; + + public X11JAWTToolkitLock(long displayHandle) { + this.displayHandle = displayHandle; + } + + public final void lock() { + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock()"); } + JAWTUtil.lockToolkit(); + X11Util.XLockDisplay(displayHandle); + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock()"); } + X11Util.XUnlockDisplay(displayHandle); + JAWTUtil.unlockToolkit(); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java index c74a62b7e..4a2c9ada3 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java @@ -60,79 +60,65 @@ public class X11JAWTWindow extends JAWTWindow { if(0==displayHandle) { displayHandle = X11Util.createThreadLocalDisplay(null); } - awtDevice.setHandle(displayHandle); + awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); } } protected int lockSurfaceImpl() throws NativeWindowException { - // JAWTUtil.lockToolkit(); - // config.getNativeGraphicsConfiguration().getScreen().getDevice().lock(); - try { - int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurface(); - return LOCK_SURFACE_NOT_READY; - } - int res = ds.Lock(); - dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; - if (!dsLocked) { - unlockSurface(); - throw new NativeWindowException("Unable to lock surface"); - } - // See whether the surface changed and if so destroy the old - // OpenGL context so it will be recreated (NOTE: removeNotify - // should handle this case, but it may be possible that race - // conditions can cause this code to be triggered -- should test - // more) - if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { - ret = LOCK_SURFACE_CHANGED; - } - dsi = ds.GetDrawingSurfaceInfo(); - if (dsi == null) { - unlockSurface(); - return LOCK_SURFACE_NOT_READY; - } - x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); - if (x11dsi == null) { - unlockSurface(); - return LOCK_SURFACE_NOT_READY; - } - drawable = x11dsi.getDrawable(); - if (drawable == 0) { - unlockSurface(); - return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); - } - return ret; - } finally { - // config.getNativeGraphicsConfiguration().getScreen().getDevice().unlock(); - // JAWTUtil.unlockToolkit(); + int ret = NativeWindow.LOCK_SUCCESS; + ds = JAWT.getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + unlockSurface(); + return LOCK_SURFACE_NOT_READY; } + int res = ds.Lock(); + dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; + if (!dsLocked) { + unlockSurface(); + throw new NativeWindowException("Unable to lock surface"); + } + // See whether the surface changed and if so destroy the old + // OpenGL context so it will be recreated (NOTE: removeNotify + // should handle this case, but it may be possible that race + // conditions can cause this code to be triggered -- should test + // more) + if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { + ret = LOCK_SURFACE_CHANGED; + } + dsi = ds.GetDrawingSurfaceInfo(); + if (dsi == null) { + unlockSurface(); + return LOCK_SURFACE_NOT_READY; + } + x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); + if (x11dsi == null) { + unlockSurface(); + return LOCK_SURFACE_NOT_READY; + } + drawable = x11dsi.getDrawable(); + if (drawable == 0) { + unlockSurface(); + return LOCK_SURFACE_NOT_READY; + } else { + updateBounds(dsi.getBounds()); + } + return ret; } protected void unlockSurfaceImpl() throws NativeWindowException { - // JAWTUtil.lockToolkit(); - // config.getNativeGraphicsConfiguration().getScreen().getDevice().lock(); - try { - if(null!=ds) { - if (null!=dsi) { - ds.FreeDrawingSurfaceInfo(dsi); - } - if (dsLocked) { - ds.Unlock(); - } - JAWT.getJAWT().FreeDrawingSurface(ds); + if(null!=ds) { + if (null!=dsi) { + ds.FreeDrawingSurfaceInfo(dsi); + } + if (dsLocked) { + ds.Unlock(); } - ds = null; - dsi = null; - x11dsi = null; - } finally { - // config.getNativeGraphicsConfiguration().getScreen().getDevice().unlock(); - // JAWTUtil.unlockToolkit(); + JAWT.getJAWT().FreeDrawingSurface(ds); } + ds = null; + dsi = null; + x11dsi = null; } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11SunJDKReflection.java index 7cca6f9f3..081975afb 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11SunJDKReflection.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11SunJDKReflection.java @@ -89,7 +89,7 @@ public class X11SunJDKReflection { } try { - return ((Integer) x11GraphicsDeviceGetScreenMethod.invoke(device, new Object[] {})).intValue(); + return ((Integer) x11GraphicsDeviceGetScreenMethod.invoke(device, null)).intValue(); } catch (Exception e) { return 0; } @@ -101,7 +101,7 @@ public class X11SunJDKReflection { } try { - return ((Long) x11GraphicsDeviceGetDisplayMethod.invoke(device, new Object[] {})).longValue(); + return ((Long) x11GraphicsDeviceGetDisplayMethod.invoke(device, null)).longValue(); } catch (Exception e) { return 0; } @@ -124,7 +124,7 @@ public class X11SunJDKReflection { } try { - return ((Integer) x11GraphicsConfigGetVisualMethod.invoke(config, new Object[] {})).intValue(); + return ((Integer) x11GraphicsConfigGetVisualMethod.invoke(config, null)).intValue(); } catch (Exception e) { return 0; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java index fbf4524a4..87324a57c 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11GraphicsConfigurationFactory.java @@ -38,13 +38,11 @@ import com.jogamp.nativewindow.impl.x11.XVisualInfo; import com.jogamp.nativewindow.impl.x11.X11Lib; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { - public AbstractGraphicsConfiguration - chooseGraphicsConfiguration(Capabilities capabilities, - CapabilitiesChooser chooser, - AbstractGraphicsScreen screen) + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( + Capabilities capabilities, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) throws IllegalArgumentException, NativeWindowException { - if(null==screen || !(screen instanceof X11GraphicsScreen)) { + if(!(screen instanceof X11GraphicsScreen)) { throw new NativeWindowException("Only valid X11GraphicsScreen are allowed"); } return new X11GraphicsConfiguration((X11GraphicsScreen)screen, capabilities, capabilities, getXVisualInfo(screen, capabilities)); @@ -58,7 +56,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor int num[] = { -1 }; long display = screen.getDevice().getHandle(); - XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); + XVisualInfo[] xvis = X11Util.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); if(xvis==null || num[0]<1) { return null; @@ -84,7 +82,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor vinfo_template.setC_class(c_class); long display = screen.getDevice().getHandle(); - XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); + XVisualInfo[] vinfos = X11Util.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/com/jogamp/nativewindow/impl/x11/X11ToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11ToolkitLock.java new file mode 100644 index 000000000..2e0e911b9 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11ToolkitLock.java @@ -0,0 +1,55 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.nativewindow.impl.x11; + +import javax.media.nativewindow.ToolkitLock; + +/** + * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} + * utilizing {@link X11Util#XLockDisplay(long)}. + * <br> + * This strategy should not be used in case XInitThreads() is being used, + * or a higher level toolkit lock is required, ie AWT lock. + */ +public class X11ToolkitLock implements ToolkitLock { + long displayHandle; + + public X11ToolkitLock(long displayHandle) { + this.displayHandle = displayHandle; + } + + public final void lock() { + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock()"); } + X11Util.XLockDisplay(displayHandle); + } + + public final void unlock() { + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock()"); } + X11Util.XUnlockDisplay(displayHandle); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java index 6871cd5f2..3e991e52e 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java @@ -38,11 +38,15 @@ import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; import com.jogamp.common.util.LongObjectHashMap; -import com.jogamp.common.util.RecursiveToolkitLock; +import com.jogamp.common.util.locks.RecursiveLock; import javax.media.nativewindow.*; import com.jogamp.nativewindow.impl.*; +import java.nio.Buffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.security.AccessController; /** * Contains a thread safe X11 utility to retrieve thread local display connection,<br> @@ -52,25 +56,58 @@ import com.jogamp.nativewindow.impl.*; * where an application heavily utilizing this class on temporary new threads.<br> */ public class X11Util { - private static final boolean DEBUG = Debug.debug("X11Util"); + private static final boolean DEBUG = Debug.debug("X11Util"); - public static final String nullDisplayName; + private static String nullDisplayName = null; + private static boolean isFirstX11ActionOnProcess = false; + private static boolean isInit = false; - static { - NWJNILibLoader.loadNativeWindow("x11"); + public static synchronized void initSingleton(boolean firstX11ActionOnProcess) { + if(!isInit) { + NWJNILibLoader.loadNativeWindow("x11"); - initialize( true ); + /** + * Always issue XInitThreads() since we have independent + * off-thread created Display connections able to utilize multithreading, ie NEWT */ + initialize( true ); + // initialize( firstX11ActionOnProcess ); + isFirstX11ActionOnProcess = firstX11ActionOnProcess; - long dpy = X11Lib.XOpenDisplay(null); - nullDisplayName = X11Lib.XDisplayString(dpy); - X11Lib.XCloseDisplay(dpy); - if(DEBUG) { - System.out.println("X11 Display(NULL) <"+nullDisplayName+">"); + if(DEBUG) { + System.out.println("X11Util.isFirstX11ActionOnProcess: "+isFirstX11ActionOnProcess); + } + isInit = true; } } - public static void initSingleton() { - // just exist to ensure static init has been run + public static boolean isFirstX11ActionOnProcess() { + return isFirstX11ActionOnProcess; + } + + public static String getNullDisplayName() { + if(null==nullDisplayName) { + synchronized(X11Util.class) { + if(null==nullDisplayName) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + long dpy = X11Lib.XOpenDisplay(null); + X11Util.XLockDisplay(dpy); + try { + nullDisplayName = X11Lib.XDisplayString(dpy); + } finally { + X11Util.XUnlockDisplay(dpy); + } + X11Lib.XCloseDisplay(dpy); + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + if(DEBUG) { + System.out.println("X11 Display(NULL) <"+nullDisplayName+">"); + } + } + } + } + return nullDisplayName; } private X11Util() {} @@ -82,7 +119,7 @@ public class X11Util { private static ThreadLocal currentDisplayMap = new ThreadLocal(); - public static class NamedDisplay extends RecursiveToolkitLock implements Cloneable { + public static class NamedDisplay extends RecursiveLock implements Cloneable { String name; long handle; int refCount; @@ -147,7 +184,7 @@ public class X11Util { name = validateDisplayName(name); NamedDisplay namedDpy = getCurrentDisplay(name); if(null==namedDpy) { - long dpy = X11Lib.XOpenDisplay(name); + long dpy = XOpenDisplay(name); if(0==dpy) { throw new NativeWindowException("X11Util.Display: Unable to create a display("+name+") connection in Thread "+Thread.currentThread().getName()); } @@ -199,7 +236,7 @@ public class X11Util { if(null==globalNamedDisplayMap.remove(dpy)) { throw new RuntimeException("Internal: "+namedDpy); } } if(!namedDpy.isUncloseable()) { - X11Lib.XCloseDisplay(dpy); + XCloseDisplay(dpy); } } else if(DEBUG) { Exception e = new Exception("X11Util.Display: Keep TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); @@ -281,7 +318,7 @@ public class X11Util { /** Returns this created named display. */ public static long createDisplay(String name) { name = validateDisplayName(name); - long dpy = X11Lib.XOpenDisplay(name); + long dpy = XOpenDisplay(name); if(0==dpy) { throw new NativeWindowException("X11Util.Display: Unable to create a display("+name+") connection. Thread "+Thread.currentThread().getName()); } @@ -292,7 +329,7 @@ public class X11Util { globalNamedDisplayMap.put(dpy, namedDpy); } if(DEBUG) { - Exception e = new Exception("X11Util.Display: Created new global "+namedDpy+". Thread "+Thread.currentThread().getName()); + Exception e = new Exception("X11Util.Display: Created new "+namedDpy+". Thread "+Thread.currentThread().getName()); e.printStackTrace(); } return namedDpy.getHandle(); @@ -312,7 +349,7 @@ public class X11Util { } if(!namedDpy.isUncloseable()) { - X11Lib.XCloseDisplay(namedDpy.getHandle()); + XCloseDisplay(namedDpy.getHandle()); } } @@ -320,42 +357,331 @@ public class X11Util { * @return If name is null, it returns the previous queried NULL display name, * otherwise the name. */ public static String validateDisplayName(String name) { - return ( null == name ) ? nullDisplayName : name ; + return ( null == name ) ? getNullDisplayName() : name ; } public static String validateDisplayName(String name, long handle) { if(null==name && 0!=handle) { - name = getNameOfDisplay(handle); + name = XDisplayString(handle); } return validateDisplayName(name); } - public static boolean setSynchronizeDisplay(long handle, boolean onoff) { - boolean res = X11Lib.XSynchronize(handle, onoff); - return res; + /******************************* + ** + ** Locked X11Lib wrapped functions + ** + *******************************/ + public static long XOpenDisplay(String arg0) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + return X11Lib.XOpenDisplay(arg0); + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + public static int XSync(long display, boolean discard) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XSync(display, discard); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static boolean XSynchronize(long display, boolean onoff) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XSynchronize(display, onoff); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static boolean XineramaEnabled(long display) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XineramaEnabled(display); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static int DefaultScreen(long display) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.DefaultScreen(display); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static long RootWindow(long display, int screen_number) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.RootWindow(display, screen_number); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static long XCreatePixmap(long display, long arg1, int arg2, int arg3, int arg4) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XCreatePixmap(display, arg1, arg2, arg3, arg4); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static String XDisplayString(long display) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XDisplayString(display); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static int XFlush(long display) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XFlush(display); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static int XFree(Buffer arg0) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + return X11Lib.XFree(arg0); + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static int XFreePixmap(long display, long arg1) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XFreePixmap(display, arg1); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static long DefaultVisualID(long display, int screen) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.DefaultVisualID(display, screen); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static long CreateDummyWindow(long display, int screen_index, long visualID) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.CreateDummyWindow(display, screen_index, visualID); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static void DestroyDummyWindow(long display, long window) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + X11Lib.DestroyDummyWindow(display, window); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static int XCloseDisplay(long display) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XCloseDisplay(display); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static XVisualInfo[] XGetVisualInfo(long display, long arg1, XVisualInfo arg2, int[] arg3, int arg3_offset) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XGetVisualInfo(display, arg1, arg2, arg3, arg3_offset); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, green_array, blue_array); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + 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) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static boolean XF86VidModeGetGammaRampSize(long display, int screen, IntBuffer size) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static boolean XF86VidModeGetGammaRampSize(long display, int screen, int[] size, int size_offset) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size, size_offset); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } + } + + public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, green_array, blue_array); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } } - public static String getNameOfDisplay(long handle) { - String name = X11Lib.XDisplayString(handle); - return name; + 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) { + NativeWindowFactory.getDefaultToolkitLock().lock(); + try { + X11Util.XLockDisplay(display); + try { + return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); + } finally { + X11Util.XUnlockDisplay(display); + } + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); + } } public static void XLockDisplay(long handle) { - if(DEBUG) { - System.out.println("... X11 Display Lock try 0x"+Long.toHexString(handle)); + if(ToolkitLock.TRACE_LOCK) { + System.out.println("+++ X11 Display Lock get 0x"+Long.toHexString(handle)); } X11Lib.XLockDisplay(handle); - if(DEBUG) { - System.out.println("+++ X11 Display Lock got 0x"+Long.toHexString(handle)); - } } public static void XUnlockDisplay(long handle) { - if(DEBUG) { + if(ToolkitLock.TRACE_LOCK) { System.out.println("--- X11 Display Lock rel 0x"+Long.toHexString(handle)); } X11Lib.XUnlockDisplay(handle); } - private static native void initialize(boolean initConcurrentThreadSupport); + private static native void initialize(boolean firstUIActionOnProcess); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index c133df5b4..b003db8f5 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -56,7 +57,15 @@ public interface AbstractGraphicsDevice extends Cloneable { */ public long getHandle(); + /** + * Optionally locking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}. + * The lock implementation must be recursive. + */ public void lock(); + /** + * Optionally unlocking the device, utilizing eg {@link javax.media.nativewindow.ToolkitLock}. + * The lock implementation must be recursive. + */ public void unlock(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index e18b7b2dc..ca0f106f5 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -32,18 +32,46 @@ package javax.media.nativewindow; +import com.jogamp.nativewindow.impl.NativeWindowFactoryImpl; + public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice { private String type; protected long handle; + protected ToolkitLock toolkitLock; + /** + * Create an instance with the system default {@link ToolkitLock}, + * gathered via {@link NativeWindowFactory#createDefaultToolkitLock()}. + * @param type + */ public DefaultGraphicsDevice(String type) { this.type = type; this.handle = 0; + setToolkitLock( NativeWindowFactory.getDefaultToolkitLock(type) ); } + /** + * Create an instance with the system default {@link ToolkitLock}. + * gathered via {@link NativeWindowFactory#createDefaultToolkitLock()}. + * @param type + * @param handle + */ public DefaultGraphicsDevice(String type, long handle) { this.type = type; this.handle = handle; + setToolkitLock( NativeWindowFactory.createDefaultToolkitLock(type, handle) ); + } + + /** + * Create an instance with the given {@link ToolkitLock} instance. + * @param type + * @param handle + * @param locker + */ + public DefaultGraphicsDevice(String type, long handle, ToolkitLock locker) { + this.type = type; + this.handle = handle; + setToolkitLock( locker ); } public Object clone() { @@ -62,10 +90,46 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice return handle; } - public void lock() { + /** + * Set the internal ToolkitLock, which is used within the + * {@link #lock()} and {@link #unlock()} implementation. + * + * @param locker the ToolkitLock, if null, {@link com.jogamp.nativewindow.impl.NullToolkitLock} is being used + */ + protected void setToolkitLock(ToolkitLock locker) { + this.toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + } + + /** + * @return the used ToolkitLock + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) + */ + public final ToolkitLock getToolkitLock() { + return toolkitLock; + } + + /** + * No lock is performed on the graphics device per default, + * instead the aggregated recursive {@link ToolkitLock#lock()} is invoked. + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) + */ + public final void lock() { + toolkitLock.lock(); } - public void unlock() { + /** + * No lock is performed on the graphics device per default, + * instead the aggregated recursive {@link ToolkitLock#unlock()} is invoked. + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) + */ + public final void unlock() { + toolkitLock.unlock(); } public String toString() { diff --git a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index 0a1a91876..75c8aea22 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -78,7 +78,7 @@ public abstract class GraphicsConfigurationFactory { if (NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { try { GraphicsConfigurationFactory factory = (GraphicsConfigurationFactory) - ReflectionUtil.createInstance("com.jogamp.nativewindow.impl.x11.X11GraphicsConfigurationFactory", new Object[] {}, + ReflectionUtil.createInstance("com.jogamp.nativewindow.impl.x11.X11GraphicsConfigurationFactory", null, GraphicsConfigurationFactory.class.getClassLoader()); registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, factory); } catch (Exception e) { @@ -198,9 +198,29 @@ public abstract class GraphicsConfigurationFactory { * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) * @see javax.media.nativewindow.DefaultGraphicsConfiguration#setChosenCapabilities(Capabilities caps) */ - public abstract AbstractGraphicsConfiguration + public final AbstractGraphicsConfiguration chooseGraphicsConfiguration(Capabilities capabilities, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) + throws IllegalArgumentException, NativeWindowException { + if(null==screen) { + throw new NativeWindowException("Screen is null"); + } + AbstractGraphicsDevice device = screen.getDevice(); + if(null==device) { + throw new NativeWindowException("Screen's Device is null"); + } + device.lock(); + try { + return chooseGraphicsConfigurationImpl(capabilities, chooser, screen); + } finally { + device.unlock(); + } + } + + protected abstract AbstractGraphicsConfiguration + chooseGraphicsConfigurationImpl(Capabilities capabilities, + CapabilitiesChooser chooser, + AbstractGraphicsScreen screen) throws IllegalArgumentException, NativeWindowException; } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java index ef45a79d3..a5b71fbf8 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java @@ -1,6 +1,5 @@ /** * Copyright 2010 JogAmp Community. 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: @@ -63,14 +62,17 @@ public interface NativeSurface extends SurfaceUpdatedListener { * This call allows recursion from the same thread.<P> * * The implementation may want to aquire the - * application level {@link com.jogamp.common.util.RecursiveToolkitLock} + * application level {@link com.jogamp.common.util.locks.RecursiveLock} * first before proceeding with a native surface lock. <P> * + * The implementation shall also invoke {@link AbstractGraphicsDevice#lock()} + * for the initial lock (recursive count zero).<P> + * * @return {@link #LOCK_SUCCESS}, {@link #LOCK_SURFACE_CHANGED} or {@link #LOCK_SURFACE_NOT_READY}. * * @throws RuntimeException after timeout when waiting for the surface lock * - * @see com.jogamp.common.util.RecursiveToolkitLock + * @see com.jogamp.common.util.locks.RecursiveLock */ public int lockSurface(); @@ -79,10 +81,13 @@ public interface NativeSurface extends SurfaceUpdatedListener { * * Shall not modify the surface handle, see {@link #lockSurface()} <P> * + * The implementation shall also invoke {@link AbstractGraphicsDevice#unlock()} + * for the final unlock (recursive count zero).<P> + * * @throws RuntimeException if surface is not locked * * @see #lockSurface - * @see com.jogamp.common.util.RecursiveToolkitLock + * @see com.jogamp.common.util.locks.RecursiveLock */ public void unlockSurface() throws NativeWindowException ; @@ -102,14 +107,6 @@ public interface NativeSurface extends SurfaceUpdatedListener { public Thread getSurfaceLockOwner(); /** - * Return the lock-exception, or null if not locked. - * - * The lock-exception is created at {@link #lockSurface()} - * and hence holds the locker's call stack. - */ - public Exception getSurfaceLockStack(); - - /** * Provide a mechanism to utilize custom (pre-) swap surface * code. This method is called before the render toolkit (e.g. JOGL) * swaps the buffer/surface. The implementation may itself apply the swapping, diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index f716e8ac9..7897460a0 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,13 +33,14 @@ package javax.media.nativewindow; -import java.lang.reflect.*; import java.security.*; import java.util.*; import com.jogamp.common.util.*; import com.jogamp.common.jvm.JVMUtil; import com.jogamp.nativewindow.impl.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; /** Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the {@link NativeWindow} interface, @@ -74,9 +76,20 @@ public abstract class NativeWindowFactory { private static String nativeOSNamePure; private static String nativeWindowingTypeCustom; private static String nativeOSNameCustom; - private static final boolean isAWTAvailable; + private static boolean isAWTAvailable; public static final String AWTComponentClassName = "java.awt.Component" ; + public static final String JAWTUtilClassName = "com.jogamp.nativewindow.impl.jawt.JAWTUtil" ; public static final String X11UtilClassName = "com.jogamp.nativewindow.impl.x11.X11Util"; + public static final String X11JAWTToolkitLockClassName = "com.jogamp.nativewindow.impl.jawt.x11.X11JAWTToolkitLock" ; + public static final String X11ToolkitLockClassName = "com.jogamp.nativewindow.impl.x11.X11ToolkitLock" ; + private static Class jawtUtilClass; + private static Method jawtUtilGetJAWTToolkitMethod; + private static Method jawtUtilInitMethod; + private static Class x11JAWTToolkitLockClass; + private static Constructor x11JAWTToolkitLockConstructor; + private static Class x11ToolkitLockClass; + private static Constructor x11ToolkitLockConstructor; + private static boolean isFirstUIActionOnProcess; /** Creates a new NativeWindowFactory instance. End users do not need to call this method. */ @@ -100,54 +113,117 @@ public abstract class NativeWindowFactory { static { JVMUtil.initSingleton(); + } - // Gather the windowing OS first - AccessControlContext acc = AccessController.getContext(); - nativeOSNamePure = Debug.getProperty("os.name", false, acc); - nativeWindowingTypePure = _getNativeWindowingType(nativeOSNamePure.toLowerCase()); - nativeOSNameCustom = Debug.getProperty("nativewindow.ws.name", true, acc); - if(null==nativeOSNameCustom||nativeOSNameCustom.length()==0) { - nativeOSNameCustom = nativeOSNamePure; - nativeWindowingTypeCustom = nativeWindowingTypePure; - } else { - nativeWindowingTypeCustom = nativeOSNameCustom; - } - - ClassLoader cl = NativeWindowFactory.class.getClassLoader(); + static boolean initialized = false; + + /** + * Static one time initialization of this factory.<br> + * This initialization method <b>must be called</b> once by the program or utilizing modules!<br> + * @param firstUIActionOnProcess Should be <code>true</code> if called before the first UI action of the running program, + * otherwise <code>false</code>. + */ + public static synchronized void initSingleton(final boolean firstUIActionOnProcess) { + if(!initialized) { + initialized = true; + + if(DEBUG) { + Throwable td = new Throwable("Info: NativeWindowFactory.initSingleton("+firstUIActionOnProcess+")"); + td.printStackTrace(); + } - if( TYPE_X11.equals(nativeWindowingTypePure) ) { - ReflectionUtil.callStaticMethod( X11UtilClassName, "initSingleton", new Class[] { }, new Object[] { }, cl ); - } + // Gather the windowing OS first + AccessControlContext acc = AccessController.getContext(); + nativeOSNamePure = Debug.getProperty("os.name", false, acc); + nativeWindowingTypePure = _getNativeWindowingType(nativeOSNamePure.toLowerCase()); + nativeOSNameCustom = Debug.getProperty("nativewindow.ws.name", true, acc); + if(null==nativeOSNameCustom||nativeOSNameCustom.length()==0) { + nativeOSNameCustom = nativeOSNamePure; + nativeWindowingTypeCustom = nativeWindowingTypePure; + } else { + nativeWindowingTypeCustom = nativeOSNameCustom; + } - registeredFactories = Collections.synchronizedMap(new HashMap()); + ClassLoader cl = NativeWindowFactory.class.getClassLoader(); - String factoryClassName = null; + if( TYPE_X11.equals(nativeWindowingTypePure) ) { + // explicit initialization of X11Util + ReflectionUtil.callStaticMethod(X11UtilClassName, "initSingleton", + new Class[] { boolean.class }, + new Object[] { new Boolean(firstUIActionOnProcess) }, cl ); + } + isFirstUIActionOnProcess = firstUIActionOnProcess; + + if( !Debug.getBooleanProperty("java.awt.headless", true, acc) && + ReflectionUtil.isClassAvailable(AWTComponentClassName, cl) && + ReflectionUtil.isClassAvailable("javax.media.nativewindow.awt.AWTGraphicsDevice", cl) ) { + + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + jawtUtilClass = Class.forName(JAWTUtilClassName, false, NativeWindowFactory.class.getClassLoader()); + jawtUtilInitMethod = jawtUtilClass.getDeclaredMethod("initSingleton", null); + jawtUtilInitMethod.setAccessible(true); + jawtUtilGetJAWTToolkitMethod = jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); + jawtUtilGetJAWTToolkitMethod.setAccessible(true); + } catch (Exception e) { + // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 + } + return null; + } + }); + if(null != jawtUtilClass && null != jawtUtilGetJAWTToolkitMethod && null != jawtUtilInitMethod) { + ReflectionUtil.callMethod(null, jawtUtilInitMethod, null); + + Object resO = ReflectionUtil.callStaticMethod(JAWTUtilClassName, "isHeadlessMode", null, null, cl ); + if(resO instanceof Boolean) { + // AWT is only available in case all above classes are available + // and AWT is not int headless mode + isAWTAvailable = ((Boolean)resO).equals(Boolean.FALSE); + } else { + isAWTAvailable = false; + } + } else { + isAWTAvailable = false; + } + } else { + isAWTAvailable = false; + } - // register our default factory -> NativeWindow - NativeWindowFactory factory = new NativeWindowFactoryImpl(); - nativeWindowClass = javax.media.nativewindow.NativeWindow.class; - registerFactory(nativeWindowClass, factory); - defaultFactory = factory; - - // We break compile-time dependencies on the AWT here to - // make it easier to run this code on mobile devices - isAWTAvailable = !Debug.getBooleanProperty("java.awt.headless", true, acc) && - ReflectionUtil.isClassAvailable(AWTComponentClassName, cl) && - ReflectionUtil.isClassAvailable("javax.media.nativewindow.awt.AWTGraphicsDevice", cl) ; - - if ( isAWTAvailable ) { - // register either our default factory or (if exist) the X11/AWT one -> AWT Component - registerFactory(ReflectionUtil.getClass(AWTComponentClassName, false, cl), factory); - } + registeredFactories = Collections.synchronizedMap(new HashMap()); + + // register our default factory -> NativeWindow + NativeWindowFactory factory = new NativeWindowFactoryImpl(); + nativeWindowClass = javax.media.nativewindow.NativeWindow.class; + registerFactory(nativeWindowClass, factory); + defaultFactory = factory; + + if ( isAWTAvailable ) { + // register either our default factory or (if exist) the X11/AWT one -> AWT Component + registerFactory(ReflectionUtil.getClass(AWTComponentClassName, false, cl), factory); + } - if(DEBUG) { - System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+ - ", defaultFactory "+factory); + if( TYPE_X11 == nativeWindowingTypePure ) { + // passing through RuntimeException if not exists intended + x11ToolkitLockClass = ReflectionUtil.getClass(X11ToolkitLockClassName, false, cl); + x11ToolkitLockConstructor = ReflectionUtil.getConstructor(x11ToolkitLockClass, new Class[] { long.class } ); + if( isAWTAvailable() ) { + x11JAWTToolkitLockClass = ReflectionUtil.getClass(X11JAWTToolkitLockClassName, false, cl); + x11JAWTToolkitLockConstructor = ReflectionUtil.getConstructor(x11JAWTToolkitLockClass, new Class[] { long.class } ); + } + } + + if(DEBUG) { + System.err.println("NativeWindowFactory firstUIActionOnProcess "+firstUIActionOnProcess); + System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory); + } } } - public static void initSingleton() { - // just exist to ensure static init has been run + /** @return true if initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, + otherwise false. */ + public static boolean isFirstUIActionOnProcess() { + return isFirstUIActionOnProcess; } /** @return true if not headless, AWT Component and NativeWindow's AWT part available */ @@ -171,6 +247,91 @@ public abstract class NativeWindowFactory { return defaultFactory; } + /** + * Provides the system default {@link ToolkitLock}, a singleton instance. + * <br> + * This is a {@link com.jogamp.nativewindow.impl.jawt.JAWTToolkitLock} + * in case of a <b>X11 system</b> <em>and</em> <b>AWT availability</b> and if + * this factory has been initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, <br> + * otherwise {@link com.jogamp.nativewindow.impl.NullToolkitLock} is returned. + */ + public static ToolkitLock getDefaultToolkitLock() { + return getDefaultToolkitLock(getNativeWindowType(false)); + } + + /** + * Provides the default {@link ToolkitLock} for <code>type</code>, a singleton instance. + * <br> + * This is a {@link com.jogamp.nativewindow.impl.jawt.JAWTToolkitLock} + * in case of a <b>X11 type</b> or <b>AWT type / X11 system</b> <em>and</em> <b>AWT availability</b> and if + * this factory has been initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, <br> + * otherwise {@link com.jogamp.nativewindow.impl.NullToolkitLock} is returned. + */ + public static ToolkitLock getDefaultToolkitLock(String type) { + if( isAWTAvailable() && !isFirstUIActionOnProcess() && + ( TYPE_X11 == type || TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) ) ) { + return getAWTToolkitLock(); + } + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + protected static ToolkitLock getAWTToolkitLock() { + Object resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitMethod, null); + + if(resO instanceof ToolkitLock) { + return (ToolkitLock) resO; + } else { + throw new RuntimeException("JAWTUtil.getJAWTToolkitLock() didn't return a ToolkitLock"); + } + } + + public static ToolkitLock getNullToolkitLock() { + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + /** + * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. + * <br> + * This is a {@link com.jogamp.nativewindow.impl.jawt.x11.X11JAWTToolkitLock} + * in case of a <b>X11 type</b> <em>and</em> <b>AWT availability</b> and if + * this factory has been initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, <br> + * or a {@link com.jogamp.nativewindow.impl.x11.X11ToolkitLock} + * in case of a <b>X11 type</b> <em>and</em> <b>no AWT availability</b> and if + * this factory has been initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, <br> + * otherwise {@link com.jogamp.nativewindow.impl.NullToolkitLock} is returned. + */ + public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { + if( TYPE_X11 == type ) { + if( 0== deviceHandle ) { + throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); + } + if( !isFirstUIActionOnProcess() ) { + if( isAWTAvailable() ) { + return createX11AWTToolkitLock(deviceHandle); + } else { + return createX11ToolkitLock(deviceHandle); + } + } + } + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) { + try { + return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + protected static ToolkitLock createX11ToolkitLock(long deviceHandle) { + try { + return (ToolkitLock) x11ToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + /** Returns the appropriate NativeWindowFactory to handle window objects of the given type. The windowClass might be {@link NativeWindow NativeWindow}, in which case the client has diff --git a/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java new file mode 100644 index 000000000..09c89ebe3 --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/ToolkitLock.java @@ -0,0 +1,45 @@ +/** + * 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 javax.media.nativewindow; + +import com.jogamp.nativewindow.impl.Debug; +import java.security.AccessController; + +/** + * Marker for a singleton global recursive blocking lock implementation, + * optionally locking a native windowing toolkit as well. + * <br> + * One use case is the AWT locking on X11, see {@link com.jogamp.nativewindow.impl.jawt.JAWTToolkitLock}. + */ +public interface ToolkitLock { + public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.TraceLock", true, AccessController.getContext()); + + public void lock(); + public void unlock(); +} diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java index d326b9159..e91261211 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java @@ -43,17 +43,18 @@ import javax.media.nativewindow.*; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import javax.media.nativewindow.AbstractGraphicsDevice; -import com.jogamp.nativewindow.impl.*; /** A wrapper for an AWT GraphicsDevice allowing it to be handled in a toolkit-independent manner. */ public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { private GraphicsDevice device; + private String subType; protected AWTGraphicsDevice(GraphicsDevice device) { super(NativeWindowFactory.TYPE_AWT); this.device = device; + this.subType = null; } public static AbstractGraphicsDevice createDevice(GraphicsDevice awtDevice) { @@ -73,14 +74,23 @@ public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl /** * In case the native handle was specified, e.g. using X11, - * we shall be able to mark it. + * we shall be able to mark it.<br> + * This will also set the subType, queried with {@link #getSubType()} + * and reset the ToolkitLock type with {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)} + * and {@link #setToolkitLock(javax.media.nativewindow.ToolkitLock)}. */ - public void setHandle(long handle) { + public void setSubType(String subType, long handle) { this.handle = handle; + this.subType = subType; + setToolkitLock( NativeWindowFactory.createDefaultToolkitLock(subType, handle) ); + } + + public String getSubType() { + return subType; } public String toString() { - return getClass().toString()+"[type "+getType()+", awtDevice "+device+", handle 0x"+Long.toHexString(getHandle())+"]"; + return getClass().toString()+"[type "+getType()+"[subType "+getSubType()+"], awtDevice "+device+", handle 0x"+Long.toHexString(getHandle())+"]"; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java index 192abf775..31744702d 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java @@ -33,14 +33,14 @@ package javax.media.nativewindow.x11; import javax.media.nativewindow.*; -import com.jogamp.nativewindow.impl.*; -import com.jogamp.nativewindow.impl.x11.X11Util; /** Encapsulates a graphics device on X11 platforms. */ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - /** Constructs a new X11GraphicsDevice corresponding to the given native display handle. */ + /** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)}. + */ public X11GraphicsDevice(long display) { super(NativeWindowFactory.TYPE_X11, display); if(0==display) { @@ -48,17 +48,19 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl } } - public Object clone() { - return super.clone(); - } - - public void lock() { - X11Util.XLockDisplay(handle); + /** + * @param display the Display connection + * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking in NEWT + */ + public X11GraphicsDevice(long display, ToolkitLock locker) { + super(NativeWindowFactory.TYPE_X11, display, locker); + if(0==display) { + throw new NativeWindowException("null display"); + } } - public void unlock() { - X11Util.XUnlockDisplay(handle); + public Object clone() { + return super.clone(); } - } diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java index 97bdc37cf..73af5f852 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java @@ -34,7 +34,6 @@ package javax.media.nativewindow.x11; import javax.media.nativewindow.*; import com.jogamp.nativewindow.impl.x11.X11Util; -import com.jogamp.nativewindow.impl.x11.X11Lib; /** Encapsulates a screen index on X11 platforms. Objects of this type are passed to {@link @@ -57,21 +56,21 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl /** Creates a new X11GraphicsScreen using a thread local display connection */ public static AbstractGraphicsScreen createDefault() { long display = X11Util.createThreadLocalDisplay(null); - int scrnIdx = X11Lib.DefaultScreen(display); + int scrnIdx = X11Util.DefaultScreen(display); return createScreenDevice(display, scrnIdx); } public long getDefaultVisualID() { // It still could be an AWT hold handle .. long display = getDevice().getHandle(); - int scrnIdx = X11Lib.DefaultScreen(display); - return X11Lib.DefaultVisualID(display, scrnIdx); + int scrnIdx = X11Util.DefaultScreen(display); + return X11Util.DefaultVisualID(display, scrnIdx); } private static int fetchScreen(X11GraphicsDevice device, int screen) { // It still could be an AWT hold handle .. long display = device.getHandle(); - if(X11Lib.XineramaEnabled(display)) { + if(X11Util.XineramaEnabled(display)) { screen = 0; // Xinerama -> 1 screen } return screen; diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 2c61a71ef..31d57240f 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -32,6 +32,7 @@ #include <string.h> #include <stdarg.h> #include <unistd.h> +#include <errno.h> #include <X11/Xlib.h> #include <X11/Xutil.h> /* Linux headers don't work properly */ @@ -85,30 +86,12 @@ Bool XF86VidModeSetGammaRamp( #ifdef VERBOSE_ON // Workaround for ancient compiler on Solaris/SPARC - // #define DBG_PRINT(args...) fprintf(stderr, args); - #define DBG_PRINT0(str) fprintf(stderr, str); - #define DBG_PRINT1(str, arg1) fprintf(stderr, str, arg1); - #define DBG_PRINT2(str, arg1, arg2) fprintf(stderr, str, arg1, arg2); - #define DBG_PRINT3(str, arg1, arg2, arg3) fprintf(stderr, str, arg1, arg2, arg3); - #define DBG_PRINT4(str, arg1, arg2, arg3, arg4) fprintf(stderr, str, arg1, arg2, arg3, arg4); - #define DBG_PRINT5(str, arg1, arg2, arg3, arg4, arg5) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5); - #define DBG_PRINT6(str, arg1, arg2, arg3, arg4, arg5, arg6) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6); - #define DBG_PRINT7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - #define DBG_PRINT8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + #define DBG_PRINT(args...) fprintf(stderr, args); #else // Workaround for ancient compiler on Solaris/SPARC - // #define DBG_PRINT(args...) - #define DBG_PRINT0(str) - #define DBG_PRINT1(str, arg1) - #define DBG_PRINT2(str, arg1, arg2) - #define DBG_PRINT3(str, arg1, arg2, arg3) - #define DBG_PRINT4(str, arg1, arg2, arg3, arg4) - #define DBG_PRINT5(str, arg1, arg2, arg3, arg4, arg5) - #define DBG_PRINT6(str, arg1, arg2, arg3, arg4, arg5, arg6) - #define DBG_PRINT7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7) - #define DBG_PRINT8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + #define DBG_PRINT(args...) #endif @@ -201,18 +184,29 @@ static XErrorHandler origErrorHandler = NULL ; static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { - _throwNewRuntimeException(NULL, x11ErrorHandlerJNIEnv, "Nativewindow X11 Error: Display %p, Code 0x%X", dpy, e->error_code); + fprintf(stderr, "Nativewindow X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, strerror(errno)); + _throwNewRuntimeException(NULL, x11ErrorHandlerJNIEnv, "Nativewindow X11 Error: Display %p, Code 0x%X, errno %s", + dpy, e->error_code, strerror(errno)); + if(NULL!=origErrorHandler) { + origErrorHandler(dpy, e); + } return 0; } -static void x11ErrorHandlerEnable(int onoff, JNIEnv * env) { +static void x11ErrorHandlerEnable(Display *dpy, int onoff, JNIEnv * env) { if(onoff) { if(NULL==origErrorHandler) { x11ErrorHandlerJNIEnv = env; + if(NULL!=dpy) { + XSync(dpy, False); + } origErrorHandler = XSetErrorHandler(x11ErrorHandler); } } else { + if(NULL!=dpy) { + XSync(dpy, False); + } XSetErrorHandler(origErrorHandler); origErrorHandler = NULL; } @@ -223,8 +217,11 @@ static XIOErrorHandler origIOErrorHandler = NULL; static int x11IOErrorHandler(Display *dpy) { - _FatalError(x11ErrorHandlerJNIEnv, "Nativewindow X11 IOError: Display %p not available", dpy); - origIOErrorHandler(dpy); + fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, XDisplayName(NULL), strerror(errno)); + // _FatalError(x11ErrorHandlerJNIEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, XDisplayName(NULL), strerror(errno)); + if(NULL!=origIOErrorHandler) { + origIOErrorHandler(dpy); + } return 0; } @@ -243,9 +240,9 @@ static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { static int _initialized=0; JNIEXPORT void JNICALL -Java_com_jogamp_nativewindow_impl_x11_X11Util_initialize(JNIEnv *env, jclass _unused, jboolean initConcurrentThreadSupport) { +Java_com_jogamp_nativewindow_impl_x11_X11Util_initialize(JNIEnv *env, jclass _unused, jboolean firstUIActionOnProcess) { if(0==_initialized) { - if( JNI_TRUE == initConcurrentThreadSupport ) { + if( JNI_TRUE == firstUIActionOnProcess ) { if( 0 == XInitThreads() ) { fprintf(stderr, "Warning: XInitThreads() failed\n"); } else { @@ -256,7 +253,6 @@ Java_com_jogamp_nativewindow_impl_x11_X11Util_initialize(JNIEnv *env, jclass _un } _initClazzAccess(env); - x11ErrorHandlerEnable(1, env); x11IOErrorHandlerEnable(1, env); _initialized=1; } @@ -284,7 +280,9 @@ Java_com_jogamp_nativewindow_impl_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBu if (arg3 != NULL) { _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); } + x11ErrorHandlerEnable((Display *) (intptr_t) arg0, 1, env); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); + x11ErrorHandlerEnable((Display *) (intptr_t) arg0, 0, env); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -305,7 +303,9 @@ Java_com_jogamp_nativewindow_impl_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass if(0==display) { _FatalError(env, "invalid display connection.."); } + x11ErrorHandlerEnable((Display *) (intptr_t) display, 1, env); r = (jlong) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); + x11ErrorHandlerEnable((Display *) (intptr_t) display, 0, env); return r; } @@ -346,7 +346,9 @@ Java_com_jogamp_nativewindow_impl_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclas if(0==display) { _FatalError(env, "invalid display connection.."); } + x11ErrorHandlerEnable((Display *) (intptr_t) display, 1, env); _res = XCloseDisplay((Display *) (intptr_t) display); + x11ErrorHandlerEnable(NULL, 0, env); return _res; } @@ -384,7 +386,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_nativewindow_impl_x11_X11Lib_CreateDummy return 0; } - XSync(dpy, False); + x11ErrorHandlerEnable(dpy, 1, env); scrn = ScreenOfDisplay(dpy, scrn_idx); @@ -400,10 +402,11 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_nativewindow_impl_x11_X11Lib_CreateDummy XFree(pVisualQuery); pVisualQuery=NULL; } - DBG_PRINT5( "X11: [CreateWindow] trying given (dpy %p, screen %d, visualID: %d, parent %p) found: %p\n", dpy, scrn_idx, (int)visualID, windowParent, visual); + DBG_PRINT( "X11: [CreateWindow] trying given (dpy %p, screen %d, visualID: %d, parent %p) found: %p\n", dpy, scrn_idx, (int)visualID, windowParent, visual); if (visual==NULL) { + x11ErrorHandlerEnable(dpy, 0, env); _throwNewRuntimeException(dpy, env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -440,9 +443,9 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_nativewindow_impl_x11_X11Lib_CreateDummy attrMask, &xswa); - XSync(dpy, False); + x11ErrorHandlerEnable(dpy, 0, env); - DBG_PRINT2( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); + DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); return (jlong) window; } @@ -464,9 +467,10 @@ JNIEXPORT void JNICALL Java_com_jogamp_nativewindow_impl_x11_X11Lib_DestroyDummy return; } - XSync(dpy, False); + x11ErrorHandlerEnable(dpy, 1, env); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - XSync(dpy, False); + x11ErrorHandlerEnable(dpy, 0, env); } + |