aboutsummaryrefslogtreecommitdiffstats
path: root/src/nativewindow/classes/jogamp/nativewindow
diff options
context:
space:
mode:
Diffstat (limited to 'src/nativewindow/classes/jogamp/nativewindow')
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/Debug.java50
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java13
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java (renamed from src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java)69
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java37
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java32
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java29
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java325
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java (renamed from src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java)64
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java149
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java50
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java47
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java100
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java98
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java147
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java27
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java303
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java14
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java362
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java15
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java28
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java33
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java15
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java56
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java318
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java50
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java85
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java96
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java22
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java71
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java7
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java70
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java35
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java485
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java52
34 files changed, 2603 insertions, 751 deletions
diff --git a/src/nativewindow/classes/jogamp/nativewindow/Debug.java b/src/nativewindow/classes/jogamp/nativewindow/Debug.java
index e07fd1b57..b7197dbca 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/Debug.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/Debug.java
@@ -1,21 +1,22 @@
/*
- * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
- *
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -28,17 +29,20 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
package jogamp.nativewindow;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
import com.jogamp.common.util.PropertyAccess;
/** Helper routines for logging and debugging. */
@@ -47,9 +51,14 @@ public class Debug extends PropertyAccess {
// Some common properties
private static final boolean verbose;
private static final boolean debugAll;
-
+
static {
- PropertyAccess.addTrustedPrefix("nativewindow.", Debug.class);
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ PropertyAccess.addTrustedPrefix("nativewindow.");
+ return null;
+ } } );
verbose = isPropertyDefined("nativewindow.verbose", true);
debugAll = isPropertyDefined("nativewindow.debug", true);
@@ -61,27 +70,18 @@ public class Debug extends PropertyAccess {
}
}
- public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias) {
- return PropertyAccess.isPropertyDefined(property, jnlpAlias, null);
- }
-
- public static String getProperty(final String property, final boolean jnlpAlias) {
- return PropertyAccess.getProperty(property, jnlpAlias, null);
- }
-
- public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias) {
- return PropertyAccess.getBooleanProperty(property, jnlpAlias, null);
- }
-
- public static boolean verbose() {
+ /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */
+ public static final void initSingleton() {}
+
+ public static final boolean verbose() {
return verbose;
}
- public static boolean debugAll() {
+ public static final boolean debugAll() {
return debugAll;
}
- public static boolean debug(String subcomponent) {
+ public static final boolean debug(String subcomponent) {
return debugAll() || isPropertyDefined("nativewindow.debug." + subcomponent, true);
}
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java
index f34b740d4..8fb819251 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -36,8 +36,9 @@ package jogamp.nativewindow;
import javax.media.nativewindow.*;
public class DefaultGraphicsConfigurationFactoryImpl extends GraphicsConfigurationFactory {
+ @Override
protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl(
- CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) {
+ CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) {
return new DefaultGraphicsConfiguration(screen, capsChosen, capsRequested);
}
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java
index 743d371b7..cadef9bf1 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2012 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -25,52 +25,55 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
-package jogamp.nativewindow.jawt.x11;
-import jogamp.nativewindow.jawt.*;
-import jogamp.nativewindow.x11.X11Lib;
-import jogamp.nativewindow.x11.X11Util;
+package jogamp.nativewindow;
+
import javax.media.nativewindow.ToolkitLock;
import com.jogamp.common.util.locks.LockFactory;
import com.jogamp.common.util.locks.RecursiveLock;
/**
- * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock}
- * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}.
- * <br>
- * This strategy should only be used if AWT is using the underlying native windowing toolkit
- * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call
- * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets.
+ * Implementing a global recursive {@link javax.media.nativewindow.ToolkitLock}.
+ * <p>
+ * This is the last resort for unstable driver where multiple X11 display connections
+ * to the same connection name are not treated thread safe within the GL/X11 driver.
+ * </p>
*/
-public class X11JAWTToolkitLock implements ToolkitLock {
- long displayHandle;
- RecursiveLock lock;
+public class GlobalToolkitLock implements ToolkitLock {
+ private static final RecursiveLock globalLock = LockFactory.createRecursiveLock();
+ private static GlobalToolkitLock singleton = new GlobalToolkitLock();
- public X11JAWTToolkitLock(long displayHandle) {
- this.displayHandle = displayHandle;
- if(!X11Util.isNativeLockAvailable()) {
- lock = LockFactory.createRecursiveLock();
- }
+ public static final GlobalToolkitLock getSingleton() {
+ return singleton;
}
+ private GlobalToolkitLock() { }
+
+ @Override
public final void lock() {
- if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); }
- JAWTUtil.lockToolkit();
- if(null == lock) {
- X11Lib.XLockDisplay(displayHandle);
- } else {
- lock.lock();
- }
+ globalLock.lock();
+ if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.lock()"); }
}
+ @Override
public final void unlock() {
- if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); }
- if(null == lock) {
- X11Lib.XUnlockDisplay(displayHandle);
- } else {
- lock.unlock();
- }
- JAWTUtil.unlockToolkit();
+ if(TRACE_LOCK) { System.err.println("GlobalToolkitLock.unlock()"); }
+ globalLock.unlock(); // implicit lock validation
+ }
+
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ globalLock.validateLocked();
+ }
+
+ @Override
+ public final void dispose() {
+ // nop
+ }
+
+ @Override
+ public String toString() {
+ return "GlobalToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+globalLock.isOwner(Thread.currentThread())+", "+globalLock.toString()+"]";
}
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java
index 99bc71c4a..e7eb13756 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java
@@ -3,14 +3,14 @@
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
@@ -20,12 +20,12 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ *
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
-
+
package jogamp.nativewindow;
@@ -37,18 +37,17 @@ import com.jogamp.common.os.Platform;
import com.jogamp.common.util.cache.TempJarCache;
public class NWJNILibLoader extends JNILibLoaderBase {
-
- public static boolean loadNativeWindow(final String ossuffix) {
- return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
- public Boolean run() {
- Platform.initSingleton();
- final String libName = "nativewindow_"+ossuffix ;
- if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) {
- addNativeJarLibs(NWJNILibLoader.class, "jogl-all", new String[] { "nativewindow" } );
- }
- return new Boolean(loadLibrary(libName, false, NWJNILibLoader.class.getClassLoader()));
- }
- }).booleanValue();
- }
-
+ public static boolean loadNativeWindow(final String ossuffix) {
+ return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ @Override
+ public Boolean run() {
+ Platform.initSingleton();
+ final String libName = "nativewindow_"+ossuffix ;
+ if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) {
+ JNILibLoaderBase.addNativeJarLibsJoglCfg(new Class<?>[] { NWJNILibLoader.class });
+ }
+ return Boolean.valueOf(loadLibrary(libName, false, NWJNILibLoader.class.getClassLoader()));
+ }
+ }).booleanValue();
+ }
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java
index 9e18439db..22ac3bd94 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -39,7 +39,6 @@ import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.ToolkitLock;
-import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.common.util.ReflectionUtil.AWTNames;
@@ -47,11 +46,12 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory {
private static final ToolkitLock nullToolkitLock = new NullToolkitLock();
public static ToolkitLock getNullToolkitLock() {
- return nullToolkitLock;
+ return nullToolkitLock;
}
-
+
// This subclass of NativeWindowFactory handles the case of
// NativeWindows being passed in
+ @Override
protected NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException {
if (winObj instanceof NativeWindow) {
// Use the NativeWindow directly
@@ -70,31 +70,31 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory {
winObj.getClass().getName() + " is unsupported; expected " +
"javax.media.nativewindow.NativeWindow or "+AWTNames.ComponentClass);
}
-
+
private Constructor<?> nativeWindowConstructor = null;
private NativeWindow getAWTNativeWindow(Object winObj, AbstractGraphicsConfiguration config) {
if (nativeWindowConstructor == null) {
try {
- String windowingType = getNativeWindowType(true);
- String windowClassName = null;
+ final String windowingType = getNativeWindowType(true);
+ final String windowClassName;
// We break compile-time dependencies on the AWT here to
// make it easier to run this code on mobile devices
- if (windowingType.equals(TYPE_WINDOWS)) {
+ if (TYPE_WINDOWS == windowingType) {
windowClassName = "jogamp.nativewindow.jawt.windows.WindowsJAWTWindow";
- } else if (windowingType.equals(TYPE_MACOSX)) {
+ } else if (TYPE_MACOSX == windowingType) {
windowClassName = "jogamp.nativewindow.jawt.macosx.MacOSXJAWTWindow";
- } else if (windowingType.equals(TYPE_X11)) {
+ } else if (TYPE_X11 == windowingType) {
// Assume Linux, Solaris, etc. Should probably test for these explicitly.
windowClassName = "jogamp.nativewindow.jawt.x11.X11JAWTWindow";
} else {
- throw new IllegalArgumentException("OS " + Platform.getOSName() + " not yet supported");
+ throw new IllegalArgumentException("Native windowing type " + windowingType + " (custom) not yet supported, platform reported native windowing type: "+getNativeWindowType(false));
}
nativeWindowConstructor = ReflectionUtil.getConstructor(
- windowClassName, new Class[] { Object.class, AbstractGraphicsConfiguration.class },
+ windowClassName, new Class[] { Object.class, AbstractGraphicsConfiguration.class },
getClass().getClassLoader());
} catch (Exception e) {
throw new IllegalArgumentException(e);
diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java
index 1af6bf279..bda20522c 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java
@@ -28,18 +28,18 @@
package jogamp.nativewindow;
+import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.ToolkitLock;
/**
- * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock}
- * without any locking. Since there is no locking it all,
- * it is intrinsically recursive.
+ * Implementing a singleton global NOP {@link javax.media.nativewindow.ToolkitLock}
+ * without any locking. Since there is no locking it all, it is intrinsically recursive.
*/
public class NullToolkitLock implements ToolkitLock {
-
/** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */
protected NullToolkitLock() { }
-
+
+ @Override
public final void lock() {
if(TRACE_LOCK) {
System.err.println("NullToolkitLock.lock()");
@@ -47,7 +47,26 @@ public class NullToolkitLock implements ToolkitLock {
}
}
+ @Override
public final void unlock() {
if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); }
}
+
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ if( NativeWindowFactory.requiresToolkitLock() ) {
+ throw new RuntimeException("NullToolkitLock does not lock, but locking is required.");
+ }
+ }
+
+ @Override
+ public final void dispose() {
+ // nop
+ }
+
+ @Override
+ public String toString() {
+ return "NullToolkitLock[]";
+ }
+
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java
new file mode 100644
index 000000000..fbff7128e
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java
@@ -0,0 +1,325 @@
+/**
+ * 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 javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.SurfaceUpdatedListener;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
+public abstract class ProxySurfaceImpl implements ProxySurface {
+ private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
+ private AbstractGraphicsConfiguration config; // control access due to delegation
+ private UpstreamSurfaceHook upstream;
+ private long surfaceHandle_old;
+ private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock();
+ private int implBitfield;
+ private boolean upstreamSurfaceHookLifecycleEnabled;
+
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ protected ProxySurfaceImpl(AbstractGraphicsConfiguration cfg, UpstreamSurfaceHook upstream, boolean ownsDevice) {
+ if(null == cfg) {
+ throw new IllegalArgumentException("null AbstractGraphicsConfiguration");
+ }
+ if(null == upstream) {
+ throw new IllegalArgumentException("null UpstreamSurfaceHook");
+ }
+ this.config = cfg;
+ this.upstream = upstream;
+ this.surfaceHandle_old = 0;
+ this.implBitfield = 0;
+ this.upstreamSurfaceHookLifecycleEnabled = true;
+ if(ownsDevice) {
+ addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ }
+
+ @Override
+ public NativeSurface getUpstreamSurface() { return null; }
+
+ @Override
+ public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; }
+
+ @Override
+ public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook) {
+ if(null == hook) {
+ throw new IllegalArgumentException("null UpstreamSurfaceHook");
+ }
+ upstream = hook;
+ }
+
+ @Override
+ public final void enableUpstreamSurfaceHookLifecycle(boolean enable) {
+ upstreamSurfaceHookLifecycleEnabled = enable;
+ }
+
+ @Override
+ public void createNotify() {
+ if(upstreamSurfaceHookLifecycleEnabled) {
+ upstream.create(this);
+ }
+ this.surfaceHandle_old = 0;
+ }
+
+ @Override
+ public void destroyNotify() {
+ if(upstreamSurfaceHookLifecycleEnabled) {
+ upstream.destroy(this);
+ if( containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ) ) {
+ final AbstractGraphicsDevice aDevice = getGraphicsConfiguration().getScreen().getDevice();
+ aDevice.close();
+ clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ invalidateImpl();
+ }
+ this.surfaceHandle_old = 0;
+ }
+
+ /**
+ * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed.
+ * @see #destroyNotify()
+ */
+ protected void invalidateImpl() {
+ throw new InternalError("UpstreamSurfaceHook given, but required method not implemented.");
+ }
+
+ @Override
+ public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
+ return config.getNativeGraphicsConfiguration();
+ }
+
+ @Override
+ public final long getDisplayHandle() {
+ return config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle();
+ }
+
+ @Override
+ public final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) {
+ config = cfg;
+ }
+
+ @Override
+ public final int getScreenIndex() {
+ return getGraphicsConfiguration().getScreen().getIndex();
+ }
+
+ @Override
+ public abstract long getSurfaceHandle();
+
+ @Override
+ public abstract void setSurfaceHandle(long surfaceHandle);
+
+ @Override
+ public final int getWidth() {
+ return upstream.getWidth(this);
+ }
+
+ @Override
+ public final int getHeight() {
+ return upstream.getHeight(this);
+ }
+
+ @Override
+ public boolean surfaceSwap() {
+ return false;
+ }
+
+ @Override
+ public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+ surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
+ surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
+ }
+
+ @Override
+ public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+ surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
+ }
+
+ @Override
+ public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
+ }
+
+ @Override
+ public int lockSurface() throws NativeWindowException, RuntimeException {
+ surfaceLock.lock();
+ int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
+
+ if ( LOCK_SURFACE_NOT_READY == res ) {
+ try {
+ final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
+ adevice.lock();
+ try {
+ res = lockSurfaceImpl();
+ if(LOCK_SUCCESS == res && surfaceHandle_old != getSurfaceHandle()) {
+ res = LOCK_SURFACE_CHANGED;
+ if(DEBUG) {
+ System.err.println("ProxySurfaceImpl: surface change 0x"+Long.toHexString(surfaceHandle_old)+" -> 0x"+Long.toHexString(getSurfaceHandle()));
+ // Thread.dumpStack();
+ }
+ }
+ } finally {
+ if (LOCK_SURFACE_NOT_READY >= res) {
+ adevice.unlock();
+ }
+ }
+ } finally {
+ if (LOCK_SURFACE_NOT_READY >= res) {
+ surfaceLock.unlock();
+ }
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public final void unlockSurface() {
+ surfaceLock.validateLocked();
+ surfaceHandle_old = getSurfaceHandle();
+
+ if (surfaceLock.getHoldCount() == 1) {
+ final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
+ try {
+ unlockSurfaceImpl();
+ } finally {
+ adevice.unlock();
+ }
+ }
+ surfaceLock.unlock();
+ }
+
+ protected abstract int lockSurfaceImpl();
+
+ protected abstract void unlockSurfaceImpl() ;
+
+ public final void validateSurfaceLocked() {
+ surfaceLock.validateLocked();
+ }
+
+ @Override
+ public final boolean isSurfaceLockedByOtherThread() {
+ return surfaceLock.isLockedByOtherThread();
+ }
+
+ @Override
+ public final Thread getSurfaceLockOwner() {
+ return surfaceLock.getOwner();
+ }
+
+ @Override
+ public final StringBuilder getUpstreamOptionBits(StringBuilder sink) {
+ if(null == sink) {
+ sink = new StringBuilder();
+ }
+ sink.append("UOB[ ");
+ if(0 == implBitfield) {
+ sink.append("]");
+ return sink;
+ }
+ boolean needsOr = false;
+ if( 0 != ( implBitfield & OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ sink.append("OWNS_SURFACE");
+ needsOr = true;
+ }
+ if( 0 != ( implBitfield & OPT_PROXY_OWNS_UPSTREAM_DEVICE ) ) {
+ if(needsOr) {
+ sink.append(" | ");
+ }
+ sink.append("OWNS_DEVICE");
+ needsOr = true;
+ }
+ if( 0 != ( implBitfield & OPT_UPSTREAM_WINDOW_INVISIBLE ) ) {
+ if(needsOr) {
+ sink.append(" | ");
+ }
+ sink.append("WINDOW_INVISIBLE");
+ needsOr = true;
+ }
+ sink.append(" ]");
+ return sink;
+ }
+
+ @Override
+ public final int getUpstreamOptionBits() { return implBitfield; }
+
+ @Override
+ public final boolean containsUpstreamOptionBits(int v) {
+ return v == ( implBitfield & v ) ;
+ }
+
+ @Override
+ public final void addUpstreamOptionBits(int v) { implBitfield |= v; }
+
+ @Override
+ public final void clearUpstreamOptionBits(int v) { implBitfield &= ~v; }
+
+ @Override
+ public StringBuilder toString(StringBuilder sink) {
+ if(null == sink) {
+ sink = new StringBuilder();
+ }
+ sink.append("displayHandle 0x" + Long.toHexString(getDisplayHandle())).
+ append("\n, surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())).
+ append("\n, size " + getWidth() + "x" + getHeight()).append("\n, ");
+ getUpstreamOptionBits(sink);
+ sink.append("\n, "+config).
+ append("\n, surfaceLock "+surfaceLock+"\n, ").
+ append(getUpstreamSurfaceHook()).
+ append("\n, upstreamSurface "+(null != getUpstreamSurface()));
+ // append("\n, upstreamSurface "+getUpstreamSurface());
+ return sink;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder msg = new StringBuilder();
+ msg.append(getClass().getSimpleName()).append("[ ");
+ toString(msg);
+ msg.append(" ]");
+ return msg.toString();
+ }
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java
index 5166ef577..f1efb8133 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2012 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -25,7 +25,8 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
-package jogamp.nativewindow.x11;
+
+package jogamp.nativewindow;
import javax.media.nativewindow.ToolkitLock;
@@ -33,38 +34,47 @@ import com.jogamp.common.util.locks.LockFactory;
import com.jogamp.common.util.locks.RecursiveLock;
/**
- * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock}
- * utilizing {@link X11Util#XLockDisplay(long)}.
- * <br>
- * This strategy should not be used in case XInitThreads() is being used,
- * or a higher level toolkit lock is required, ie AWT lock.
+ * Implementing a resource based recursive {@link javax.media.nativewindow.ToolkitLock}.
+ * <p>
+ * A resource handle maybe used within a unique object
+ * and can be synchronized across threads via an instance of ResourceToolkitLock.
+ * </p>
*/
-public class X11ToolkitLock implements ToolkitLock {
- long displayHandle;
- RecursiveLock lock;
+public class ResourceToolkitLock implements ToolkitLock {
+ public static final ResourceToolkitLock create() {
+ return new ResourceToolkitLock();
+ }
+
+ private final RecursiveLock lock;
- public X11ToolkitLock(long displayHandle) {
- this.displayHandle = displayHandle;
- if(!X11Util.isNativeLockAvailable()) {
- lock = LockFactory.createRecursiveLock();
- }
+ private ResourceToolkitLock() {
+ this.lock = LockFactory.createRecursiveLock();
}
+ @Override
public final void lock() {
- if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); }
- if(null == lock) {
- X11Lib.XLockDisplay(displayHandle);
- } else {
- lock.lock();
- }
+ lock.lock();
+ if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.lock()"); }
}
+ @Override
public final void unlock() {
- if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); }
- if(null == lock) {
- X11Lib.XUnlockDisplay(displayHandle);
- } else {
- lock.unlock();
- }
+ if(TRACE_LOCK) { System.err.println("ResourceToolkitLock.unlock()"); }
+ lock.unlock(); // implicit lock validation
+ }
+
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ lock.validateLocked();
+ }
+
+ @Override
+ public final void dispose() {
+ // nop
+ }
+
+ @Override
+ public String toString() {
+ return "ResourceToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString()+"]";
}
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java
new file mode 100644
index 000000000..7b74e1f1f
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.nativewindow;
+
+import java.util.Iterator;
+
+import javax.media.nativewindow.ToolkitLock;
+
+import com.jogamp.common.util.LongObjectHashMap;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+
+/**
+ * Implementing a shared resource based recursive {@link javax.media.nativewindow.ToolkitLock}.
+ * <p>
+ * A resource handle maybe used within many objects
+ * and can be synchronized across threads via an unique instance of SharedResourceToolkitLock.
+ * </p>
+ * <p>
+ * Implementation holds a synchronized map from handle to reference counted {@link SharedResourceToolkitLock}.
+ * New elements are added via {@link #get(long)} if new
+ * and removed via {@link #dispose()} if no more referenced.
+ * </p>
+ */
+public class SharedResourceToolkitLock implements ToolkitLock {
+ private static final LongObjectHashMap handle2Lock;
+ static {
+ handle2Lock = new LongObjectHashMap();
+ handle2Lock.setKeyNotFoundValue(null);
+ }
+
+ /**
+ * @return number of unclosed EGL Displays.<br>
+ */
+ public static int shutdown(boolean verbose) {
+ if(DEBUG || verbose || handle2Lock.size() > 0 ) {
+ System.err.println("SharedResourceToolkitLock: Shutdown (open: "+handle2Lock.size()+")");
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ if( handle2Lock.size() > 0) {
+ dumpOpenDisplayConnections();
+ }
+ }
+ return handle2Lock.size();
+ }
+
+ public static void dumpOpenDisplayConnections() {
+ System.err.println("SharedResourceToolkitLock: Open ResourceToolkitLock's: "+handle2Lock.size());
+ int i=0;
+ for(Iterator<LongObjectHashMap.Entry> iter = handle2Lock.iterator(); iter.hasNext(); i++) {
+ final LongObjectHashMap.Entry e = iter.next();
+ System.err.println("SharedResourceToolkitLock: Open["+i+"]: "+e.value);
+ }
+ }
+
+ public static final SharedResourceToolkitLock get(long handle) {
+ SharedResourceToolkitLock res;
+ synchronized(handle2Lock) {
+ res = (SharedResourceToolkitLock) handle2Lock.get(handle);
+ if( null == res ) {
+ res = new SharedResourceToolkitLock(handle);
+ res.refCount++;
+ handle2Lock.put(handle, res);
+ if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * NEW *: "+res); }
+ } else {
+ res.refCount++;
+ if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * EXIST *: "+res); }
+ }
+ }
+ return res;
+ }
+
+ private final RecursiveLock lock;
+ private final long handle;
+ private volatile int refCount;
+
+ private SharedResourceToolkitLock(long handle) {
+ this.lock = LockFactory.createRecursiveLock();
+ this.handle = handle;
+ this.refCount = 0;
+ }
+
+
+ @Override
+ public final void lock() {
+ lock.lock();
+ if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.lock()"); }
+ }
+
+ @Override
+ public final void unlock() {
+ if(TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.unlock()"); }
+ lock.unlock();
+ }
+
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ lock.validateLocked();
+ }
+
+ @Override
+ public final void dispose() {
+ if(0 < refCount) { // volatile OK
+ synchronized(handle2Lock) {
+ refCount--;
+ if(0 == refCount) {
+ if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * REMOV *: "+this); }
+ handle2Lock.remove(handle);
+ } else {
+ if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * DOWN *: "+this); }
+ }
+ }
+ } else {
+ if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * NULL *: "+this); }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SharedResourceToolkitLock[refCount "+refCount+", handle 0x"+Long.toHexString(handle)+", obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString()+"]";
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java
index 4877d5c4f..0b033955e 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java
@@ -3,14 +3,14 @@
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
@@ -20,7 +20,7 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ *
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
@@ -34,50 +34,58 @@ 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>();
+ private final Object surfaceUpdatedListenersLock = new Object();
+ private final ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>();
+ private volatile boolean isEmpty = true;
//
// Management Utils
- //
- public int size() { return surfaceUpdatedListeners.size(); }
- public SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); }
-
+ //
+ public final int size() { return surfaceUpdatedListeners.size(); }
+ public final SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); }
+
//
// Implementation of NativeSurface SurfaceUpdatedListener methods
- //
-
- public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+ //
+
+ public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
addSurfaceUpdatedListener(-1, l);
}
- public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l)
+ public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l)
throws IndexOutOfBoundsException
{
if(l == null) {
return;
}
synchronized(surfaceUpdatedListenersLock) {
- if(0>index) {
- index = surfaceUpdatedListeners.size();
+ if(0>index) {
+ index = surfaceUpdatedListeners.size();
}
surfaceUpdatedListeners.add(index, l);
+ isEmpty = false;
}
}
- public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
+ public final boolean removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
if (l == null) {
- return;
+ return false;
}
synchronized(surfaceUpdatedListenersLock) {
- surfaceUpdatedListeners.remove(l);
+ final boolean res = surfaceUpdatedListeners.remove(l);
+ isEmpty = 0 == surfaceUpdatedListeners.size();
+ return res;
}
}
- public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ @Override
+ public final void surfaceUpdated(Object updater, NativeSurface ns, long when) {
+ if( isEmpty ) {
+ return;
+ }
synchronized(surfaceUpdatedListenersLock) {
for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) {
- SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i);
+ final SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i);
l.surfaceUpdated(updater, ns, when);
}
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java
new file mode 100644
index 000000000..47b3e63fa
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java
@@ -0,0 +1,47 @@
+package jogamp.nativewindow;
+
+import javax.media.nativewindow.NativeWindowFactory;
+
+/**
+ * Marker interface.
+ * <p>
+ * Implementation requires to provide static methods:
+ * <pre>
+ public static void initSingleton() {}
+
+ public static void shutdown() {}
+
+ public static boolean requiresToolkitLock() {}
+
+ public static boolean hasThreadingIssues() {}
+ * </pre>
+ * Above static methods are invoked by {@link NativeWindowFactory#initSingleton()},
+ * or {@link NativeWindowFactory#shutdown()} via reflection.
+ * </p>
+ */
+public interface ToolkitProperties {
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
+ // void initSingleton();
+
+ /**
+ * Cleanup resources.
+ * <p>
+ * Called by {@link NativeWindowFactory#shutdown()}
+ * </p>
+ */
+ // void shutdown();
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
+ // boolean requiresToolkitLock();
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
+ // boolean hasThreadingIssues();
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
new file mode 100644
index 000000000..f622db8cc
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java
@@ -0,0 +1,100 @@
+/**
+ * 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 javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+/**
+ * Generic Surface implementation which wraps an existing window handle.
+ *
+ * @see ProxySurface
+ */
+public class WrappedSurface extends ProxySurfaceImpl {
+ protected long surfaceHandle;
+
+ /**
+ * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information,
+ * which is being passed to the {@link ProxySurface} instance.
+ *
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined
+ * @param initialWidth
+ * @param initialHeight
+ * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, boolean ownsDevice) {
+ super(cfg, new UpstreamSurfaceHookMutableSize(initialWidth, initialHeight), ownsDevice);
+ surfaceHandle=handle;
+ }
+
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise <code>false</code>.
+ */
+ public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, UpstreamSurfaceHook upstream, boolean ownsDevice) {
+ super(cfg, upstream, ownsDevice);
+ surfaceHandle=handle;
+ }
+
+ @Override
+ protected void invalidateImpl() {
+ surfaceHandle = 0;
+ }
+
+ @Override
+ public final long getSurfaceHandle() {
+ return surfaceHandle;
+ }
+
+ @Override
+ public final void setSurfaceHandle(long surfaceHandle) {
+ this.surfaceHandle=surfaceHandle;
+ }
+
+ @Override
+ protected final int lockSurfaceImpl() {
+ return LOCK_SUCCESS;
+ }
+
+ @Override
+ protected final void unlockSurfaceImpl() {
+ }
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java
new file mode 100644
index 000000000..edb65eb06
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java
@@ -0,0 +1,98 @@
+package jogamp.nativewindow;
+
+import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.NativeWindow;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+import javax.media.nativewindow.util.Insets;
+import javax.media.nativewindow.util.InsetsImmutable;
+import javax.media.nativewindow.util.Point;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSizePos;
+
+public class WrappedWindow extends WrappedSurface implements NativeWindow {
+ private final InsetsImmutable insets = new Insets(0, 0, 0, 0);
+ private long windowHandle;
+
+ /**
+ * Utilizes a {@link UpstreamSurfaceHookMutableSizePos} to hold the size and postion information,
+ * which is being passed to the {@link ProxySurface} instance.
+ *
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param surfaceHandle the wrapped pre-existing native surface handle, maybe 0 if not yet determined
+ * @param initialX
+ * @param initialY
+ * @param initialWidth
+ * @param initialHeight
+ * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ public WrappedWindow(AbstractGraphicsConfiguration cfg, long surfaceHandle, int initialX, int initialY, int initialWidth, int initialHeight, boolean ownsDevice, long windowHandle) {
+ this(cfg, surfaceHandle, new UpstreamSurfaceHookMutableSizePos(initialX, initialY, initialWidth, initialHeight), ownsDevice, windowHandle);
+ }
+
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param surfaceHandle the wrapped pre-existing native surface handle, maybe 0 if not yet determined
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise <code>false</code>.
+ */
+ public WrappedWindow(AbstractGraphicsConfiguration cfg, long surfaceHandle, UpstreamSurfaceHookMutableSizePos upstream, boolean ownsDevice, long windowHandle) {
+ super(cfg, surfaceHandle, upstream, ownsDevice);
+ this.windowHandle = windowHandle;
+ }
+
+ @Override
+ protected void invalidateImpl() {
+ super.invalidateImpl();
+ windowHandle = 0;
+ }
+
+ @Override
+ public void destroy() {
+ destroyNotify();
+ }
+
+ @Override
+ public NativeWindow getParent() {
+ return null;
+ }
+
+ @Override
+ public long getWindowHandle() {
+ return windowHandle;
+ }
+
+ @Override
+ public InsetsImmutable getInsets() {
+ return insets;
+ }
+
+ @Override
+ public int getX() {
+ return ((UpstreamSurfaceHookMutableSizePos)getUpstreamSurfaceHook()).getX();
+ }
+
+ @Override
+ public int getY() {
+ return ((UpstreamSurfaceHookMutableSizePos)getUpstreamSurfaceHook()).getY();
+ }
+
+ @Override
+ public Point getLocationOnScreen(Point point) {
+ if(null!=point) {
+ return point;
+ } else {
+ return new Point(0, 0);
+ }
+ }
+
+ @Override
+ public boolean hasFocus() {
+ return false;
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java
index d77cd75ef..069cffeb8 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java
@@ -27,15 +27,27 @@
*/
package jogamp.nativewindow.awt;
+import java.awt.Cursor;
+import java.awt.FocusTraversalPolicy;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Toolkit;
import java.awt.Window;
import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+
+import javax.swing.JComponent;
import javax.swing.JFrame;
+import javax.swing.JRootPane;
import javax.swing.WindowConstants;
-
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.WindowClosingProtocol;
+import javax.media.nativewindow.util.PixelRectangle;
+import javax.media.nativewindow.util.PixelFormat;
+import javax.media.nativewindow.util.PixelFormatUtil;
import javax.swing.MenuSelectionManager;
public class AWTMisc {
@@ -69,12 +81,145 @@ public class AWTMisc {
}
/**
+ * Return insets of the component w/o traversing up to parent,
+ * i.e. trying Window and JComponent.
+ * <p>
+ * Exception is JRootPane.
+ * Return it's parent's Window component's insets if available,
+ * otherwise return JRootPane's insets.<br>
+ * This is due to <i>experience</i> that <i>some</i> JRootPane's
+ * do not expose valid insets value.
+ * </p>
+ * @param topLevelOnly if true only returns insets of top-level components, i.e. Window and JRootPanel,
+ * otherwise for JComponent as well.
+ */
+ public static Insets getInsets(Component c, boolean topLevelOnly) {
+ if( c instanceof Window ) {
+ return ((Window)c).getInsets();
+ }
+ if( c instanceof JRootPane ) {
+ final Window w = getWindow(c);
+ if( null != w ) {
+ return w.getInsets();
+ }
+ return ((JRootPane)c).getInsets();
+ }
+ if( !topLevelOnly && c instanceof JComponent ) {
+ return ((JComponent)c).getInsets();
+ }
+ return null;
+ }
+
+ public static interface ComponentAction {
+ /**
+ * @param c the component to perform the action on
+ */
+ public void run(Component c);
+ }
+
+ public static int performAction(Container c, Class<?> cType, ComponentAction action) {
+ int count = 0;
+ final int cc = c.getComponentCount();
+ for(int i=0; i<cc; i++) {
+ final Component e = c.getComponent(i);
+ if( e instanceof Container ) {
+ count += performAction((Container)e, cType, action);
+ } else if( cType.isInstance(e) ) {
+ action.run(e);
+ count++;
+ }
+ }
+ // we come at last ..
+ if( cType.isInstance(c) ) {
+ action.run(c);
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Traverse to the next forward or backward component using the
+ * container's FocusTraversalPolicy.
+ *
+ * @param comp the assumed current focuse component
+ * @param forward if true, returns the next focus component, otherwise the previous one.
+ * @return
+ */
+ public static Component getNextFocus(Component comp, boolean forward) {
+ Container focusContainer = comp.getFocusCycleRootAncestor();
+ while ( focusContainer != null &&
+ ( !focusContainer.isShowing() || !focusContainer.isFocusable() || !focusContainer.isEnabled() ) )
+ {
+ comp = focusContainer;
+ focusContainer = comp.getFocusCycleRootAncestor();
+ }
+ Component next = null;
+ if (focusContainer != null) {
+ final FocusTraversalPolicy policy = focusContainer.getFocusTraversalPolicy();
+ next = forward ? policy.getComponentAfter(focusContainer, comp) : policy.getComponentBefore(focusContainer, comp);
+ if (next == null) {
+ next = policy.getDefaultComponent(focusContainer);
+ }
+ }
+ return next;
+ }
+
+ /**
* Issue this when your non AWT toolkit gains focus to clear AWT menu path
*/
public static void clearAWTMenus() {
MenuSelectionManager.defaultManager().clearSelectedPath();
}
+ static final HashMap<Integer, Cursor> cursorMap = new HashMap<Integer, Cursor>();
+ static final Cursor nulCursor;
+ static {
+ final Toolkit toolkit = Toolkit.getDefaultToolkit();
+ final BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
+ nulCursor = toolkit.createCustomCursor(img, new Point(0,0), "nullCursor");
+ }
+
+ public static synchronized Cursor getNullCursor() { return nulCursor; }
+
+ public static synchronized Cursor getCursor(PixelRectangle pixelrect, Point hotSpot) {
+ // 31 * x == (x << 5) - x
+ int hash = 31 + pixelrect.hashCode();
+ hash = ((hash << 5) - hash) + hotSpot.hashCode();
+ final Integer key = Integer.valueOf(hash);
+
+ Cursor cursor = cursorMap.get(key);
+ if( null == cursor ) {
+ cursor = createCursor(pixelrect, hotSpot);
+ cursorMap.put(key, cursor);
+ }
+ return cursor;
+ }
+ private static synchronized Cursor createCursor(PixelRectangle pixelrect, Point hotSpot) {
+ final int width = pixelrect.getSize().getWidth();
+ final int height = pixelrect.getSize().getHeight();
+ final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // PixelFormat.BGRA8888
+ final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() {
+ public void store(int x, int y, int pixel) {
+ img.setRGB(x, y, pixel);
+ }
+ @Override
+ public final PixelFormat getPixelformat() {
+ return PixelFormat.BGRA8888;
+ }
+ @Override
+ public int getStride() {
+ return width*4;
+ }
+ @Override
+ public final boolean isGLOriented() {
+ return false;
+ }
+ };
+ PixelFormatUtil.convert32(imgSink, pixelrect);
+ final Toolkit toolkit = Toolkit.getDefaultToolkit();
+ return toolkit.createCustomCursor(img, hotSpot, pixelrect.toString());
+ }
+
public static WindowClosingProtocol.WindowClosingMode AWT2NWClosingOperation(int awtClosingOperation) {
switch (awtClosingOperation) {
case WindowConstants.DISPOSE_ON_CLOSE:
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java
index 2377c2be6..a5da41424 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -28,11 +28,11 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
@@ -47,20 +47,21 @@ import java.awt.Toolkit;
import java.security.AccessController;
import java.security.PrivilegedAction;
-public class JAWTJNILibLoader extends NWJNILibLoader {
+public class JAWTJNILibLoader extends NWJNILibLoader {
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
// Make sure that awt.dll is loaded before loading jawt.dll. Otherwise
// a Dialog with "awt.dll not found" might pop up.
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4481947.
Toolkit.getDefaultToolkit();
-
+
// Must pre-load JAWT on all non-Mac platforms to
// ensure references from jogl_awt shared object
// will succeed since JAWT shared object isn't in
// default library path
- if ( ! NativeWindowFactory.TYPE_MACOSX.equals( NativeWindowFactory.getNativeWindowType(false) ) ) {
+ if ( NativeWindowFactory.TYPE_MACOSX != NativeWindowFactory.getNativeWindowType(false) ) {
try {
loadLibrary("jawt", null, true, JAWTJNILibLoader.class.getClassLoader());
} catch (Throwable t) {
@@ -74,9 +75,9 @@ public class JAWTJNILibLoader extends NWJNILibLoader {
}
});
}
-
+
public static void initSingleton() {
- // just exist to ensure static init has been run
+ // just exist to ensure static init has been run
}
-
+
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
index 8098bdb1b..5a1d915ce 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
@@ -48,25 +48,28 @@ import java.util.ArrayList;
import java.util.Map;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.NativeWindowFactory;
import javax.media.nativewindow.ToolkitLock;
import jogamp.nativewindow.Debug;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionNumber;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
public class JAWTUtil {
public static final boolean DEBUG = Debug.debug("JAWT");
/** OSX JAWT version option to use CALayer */
public static final int JAWT_MACOSX_USE_CALAYER = 0x80000000;
-
+
/** OSX JAWT CALayer availability on Mac OS X >= 10.6 Update 4 (recommended) */
public static final VersionNumber JAWT_MacOSXCALayerMinVersion = new VersionNumber(10,6,4);
-
+
/** OSX JAWT CALayer required with Java >= 1.7.0 (implies OS X >= 10.7 */
- public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = new VersionNumber(1,7,0);
-
+ public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = Platform.Version17;
+
// See whether we're running in headless mode
private static final boolean headlessMode;
private static final JAWT jawtLockObject;
@@ -79,52 +82,170 @@ public class JAWTUtil {
private static final Method sunToolkitAWTUnlockMethod;
private static final boolean hasSunToolkitAWTLock;
+ private static final RecursiveLock jawtLock;
private static final ToolkitLock jawtToolkitLock;
private static class PrivilegedDataBlob1 {
PrivilegedDataBlob1() {
ok = false;
- }
+ }
Method sunToolkitAWTLockMethod;
Method sunToolkitAWTUnlockMethod;
boolean ok;
}
-
+
/**
* Returns true if this platform's JAWT implementation supports offscreen layer.
*/
public static boolean isOffscreenLayerSupported() {
- return Platform.OS_TYPE == Platform.OSType.MACOS &&
- Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0;
+ return Platform.OS_TYPE == Platform.OSType.MACOS &&
+ Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0;
}
-
+
/**
* Returns true if this platform's JAWT implementation requires using offscreen layer.
*/
public static boolean isOffscreenLayerRequired() {
- return Platform.OS_TYPE == Platform.OSType.MACOS &&
- Platform.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0;
+ return Platform.OS_TYPE == Platform.OSType.MACOS &&
+ Platform.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0;
+ }
+
+ /**
+ * CALayer size needs to be set using the AWT component size.
+ * <p>
+ * AWT's super-calayer, i.e. the AWT's own component CALayer,
+ * does not layout our root-calayer in respect to this component's
+ * position and size, at least when resizing programmatically.
+ * </p>
+ * <p>
+ * As of today, this flag is enabled for all known AWT versions.
+ * </p>
+ * <p>
+ * Sync w/ NativeWindowProtocols.h
+ * </p>
+ */
+ public static final int JAWT_OSX_CALAYER_QUIRK_SIZE = 1 << 0;
+
+ /**
+ * CALayer position needs to be set to zero.
+ * <p>
+ * AWT's super-calayer, i.e. the AWT's own component CALayer,
+ * has a broken layout and needs it's sub-layers to be located at position 0/0.
+ * </p>
+ * <p>
+ * See <code>http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172187</code>.
+ * </p>
+ * <p>
+ * Further more a re-layout seems to be required in this case,
+ * i.e. a programmatic forced resize +1 and it's inverted resize -1.
+ * </p>
+ * <p>
+ * This flag is enabled w/ AWT < 1.7.0_40.
+ * </p>
+ * <p>
+ * Sync w/ NativeWindowProtocols.h
+ * </p>
+ */
+ public static final int JAWT_OSX_CALAYER_QUIRK_POSITION = 1 << 1;
+
+ /**
+ * CALayer position needs to be derived from AWT position
+ * in relation to super CALayer.
+ * <p>
+ * AWT's super-calayer, i.e. the AWT top-container's CALayer,
+ * does not layout our root-calayer in respect to this component's
+ * position and size, at least when resizing programmatically.
+ * </p>
+ * <p>
+ * CALayer position has origin 0/0 at bottom/left,
+ * where AWT component has origin 0/0 at top/left.
+ * </p>
+ * <p>
+ * The super-calayer bounds exclude the frame's heavyweight border/insets.
+ * </p>
+ * <p>
+ * The super-calayer lies within the AWT top-container client space (content).
+ * </p>
+ * <p>
+ * Component's location in super-calayer:
+ * <pre>
+ p0 = c.locationOnScreen();
+ p0 -= c.getOutterComp.getPos();
+ p0 -= c.getOutterComp.getInsets();
+ * </pre>
+ * Where 'locationOnScreen()' is:
+ * <pre>
+ p0 = 0/0;
+ while( null != c ) {
+ p0 += c.getPos();
+ }
+ * </pre>
+ * </p>
+ * <p>
+ * This flags also sets {@link #JAWT_OSX_CALAYER_QUIRK_SIZE},
+ * i.e. they are related.
+ * </p>
+ * <p>
+ * As of today, this flag is enabled for w/ AWT >= 1.7.0_40.
+ * </p>
+ * <p>
+ * Sync w/ NativeWindowProtocols.h
+ * </p>
+ */
+ public static final int JAWT_OSX_CALAYER_QUIRK_LAYOUT = 1 << 2;
+
+ /**
+ * Returns bitfield of required JAWT OSX CALayer quirks to mediate AWT impl. bugs.
+ * <p>
+ * Returns zero, if platform is not {@link Platform.OSType#MACOS}
+ * or not supporting CALayer, i.e. OSX < 10.6.4.
+ * </p>
+ * <p>
+ * Otherwise includes
+ * <ul>
+ * <li>{@link #JAWT_OSX_CALAYER_QUIRK_SIZE} (always)</li>
+ * <li>{@link #JAWT_OSX_CALAYER_QUIRK_POSITION} if JVM < 1.7.0_40</li>
+ * <li>{@link #JAWT_OSX_CALAYER_QUIRK_LAYOUT} if JVM >= 1.7.0_40</li>
+ * </ul>
+ * </p>
+ */
+ public static int getOSXCALayerQuirks() {
+ int res = 0;
+ if( Platform.OS_TYPE == Platform.OSType.MACOS &&
+ Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0 ) {
+
+ /** Knowing impl. all expose the SIZE bug */
+ res |= JAWT_OSX_CALAYER_QUIRK_SIZE;
+
+ final int c = Platform.JAVA_VERSION_NUMBER.compareTo(Platform.Version17);
+ if( c < 0 || c == 0 && Platform.JAVA_VERSION_UPDATE < 40 ) {
+ res |= JAWT_OSX_CALAYER_QUIRK_POSITION;
+ } else {
+ res |= JAWT_OSX_CALAYER_QUIRK_LAYOUT;
+ }
+ }
+ return res;
}
-
+
/**
* @param useOffscreenLayerIfAvailable
* @return
*/
public static JAWT getJAWT(boolean useOffscreenLayerIfAvailable) {
- final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4;
+ final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4;
JAWT jawt = JAWT.create();
-
+
// default queries
- boolean tryOffscreenLayer = false;
- boolean tryOnscreenLayer = true;
+ boolean tryOffscreenLayer;
+ boolean tryOnscreen;
int jawt_version_flags_offscreen = jawt_version_flags;
-
+
if(isOffscreenLayerRequired()) {
if(Platform.OS_TYPE == Platform.OSType.MACOS) {
if(Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0) {
jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER;
tryOffscreenLayer = true;
- tryOnscreenLayer = false;
+ tryOnscreen = false;
} else {
throw new RuntimeException("OSX: Invalid version of Java ("+Platform.JAVA_VERSION_NUMBER+") / OS X ("+Platform.OS_VERSION_NUMBER+")");
}
@@ -135,11 +256,18 @@ public class JAWTUtil {
if(Platform.OS_TYPE == Platform.OSType.MACOS) {
jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER;
tryOffscreenLayer = true;
+ tryOnscreen = true;
} else {
throw new InternalError("offscreen requested and supported, but n/a for: "+Platform.OS_TYPE);
}
+ } else {
+ tryOffscreenLayer = false;
+ tryOnscreen = true;
+ }
+ if(DEBUG) {
+ System.err.println("JAWTUtil.getJAWT(tryOffscreenLayer "+tryOffscreenLayer+", tryOnscreen "+tryOnscreen+")");
}
-
+
StringBuilder errsb = new StringBuilder();
if(tryOffscreenLayer) {
errsb.append("Offscreen 0x").append(Integer.toHexString(jawt_version_flags_offscreen));
@@ -147,22 +275,22 @@ public class JAWTUtil {
return jawt;
}
}
- if(tryOnscreenLayer) {
+ if(tryOnscreen) {
if(tryOffscreenLayer) {
errsb.append(", ");
}
errsb.append("Onscreen 0x").append(Integer.toHexString(jawt_version_flags));
if( JAWT.getJAWT(jawt, jawt_version_flags) ) {
return jawt;
- }
+ }
}
throw new RuntimeException("Unable to initialize JAWT, trials: "+errsb.toString());
}
-
+
public static boolean isJAWTUsingOffscreenLayer(JAWT jawt) {
return 0 != ( jawt.getCachedVersion() & JAWTUtil.JAWT_MACOSX_USE_CALAYER );
}
-
+
static {
if(DEBUG) {
System.err.println("JAWTUtil initialization (JAWT/JNI/...");
@@ -191,10 +319,11 @@ public class JAWTUtil {
isQueueFlusherThread = m;
j2dExist = ok;
- PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
PrivilegedDataBlob1 d = new PrivilegedDataBlob1();
- try {
+ try {
final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit");
d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{});
d.sunToolkitAWTLockMethod.setAccessible(true);
@@ -209,7 +338,7 @@ public class JAWTUtil {
});
sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod;
sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod;
-
+
boolean _hasSunToolkitAWTLock = false;
if ( pdb1.ok ) {
try {
@@ -221,15 +350,30 @@ public class JAWTUtil {
}
hasSunToolkitAWTLock = _hasSunToolkitAWTLock;
// hasSunToolkitAWTLock = false;
+ jawtLock = LockFactory.createRecursiveLock();
jawtToolkitLock = new ToolkitLock() {
+ @Override
public final void lock() {
JAWTUtil.lockToolkit();
- }
+ }
+ @Override
public final void unlock() {
JAWTUtil.unlockToolkit();
}
- };
+ @Override
+ public final void validateLocked() throws RuntimeException {
+ JAWTUtil.validateLocked();
+ }
+ @Override
+ public final void dispose() {
+ // nop
+ }
+ @Override
+ public String toString() {
+ return "JAWTToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+jawtLock.isOwner(Thread.currentThread())+", "+jawtLock+"]";
+ }
+ };
// trigger native AWT toolkit / properties initialization
Map<?,?> desktophints = null;
@@ -239,6 +383,7 @@ public class JAWTUtil {
} else {
final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1);
EventQueue.invokeAndWait(new Runnable() {
+ @Override
public void run() {
Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"));
if(null!=_desktophints) {
@@ -260,13 +405,22 @@ public class JAWTUtil {
System.err.println("JAWTUtil: Is headless " + headlessMode);
int hints = ( null != desktophints ) ? desktophints.size() : 0 ;
System.err.println("JAWTUtil: AWT Desktop hints " + hints);
+ System.err.println("JAWTUtil: OffscreenLayer Supported: "+isOffscreenLayerSupported()+" - Required "+isOffscreenLayerRequired());
}
}
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ */
public static void initSingleton() {
// just exist to ensure static init has been run
}
+ /**
+ * Called by {@link NativeWindowFactory#shutdown()}
+ */
+ public static void shutdown() {
+ }
public static boolean hasJava2D() {
return j2dExist;
@@ -287,58 +441,69 @@ public class JAWTUtil {
}
/**
- * Locks the AWT's global ReentrantLock.<br>
- *
+ * Locks the AWT's global ReentrantLock.
+ * <p>
* JAWT's native Lock() function calls SunToolkit.awtLock(),
- * which just uses AWT's global ReentrantLock.<br>
+ * which just uses AWT's global ReentrantLock.
+ * </p>
+ * <p>
+ * AWT locking is wrapped through a recursive lock object.
+ * </p>
*/
- private static void awtLock() {
- if(hasSunToolkitAWTLock) {
- try {
- sunToolkitAWTLockMethod.invoke(null, (Object[])null);
- } catch (Exception e) {
- throw new NativeWindowException("SunToolkit.awtLock failed", e);
+ public static void lockToolkit() throws NativeWindowException {
+ jawtLock.lock();
+ if( 1 == jawtLock.getHoldCount() ) {
+ if(!headlessMode && !isJava2DQueueFlusherThread()) {
+ if(hasSunToolkitAWTLock) {
+ try {
+ sunToolkitAWTLockMethod.invoke(null, (Object[])null);
+ } catch (Exception e) {
+ throw new NativeWindowException("SunToolkit.awtLock failed", e);
+ }
+ } else {
+ jawtLockObject.Lock();
+ }
}
- } else {
- jawtLockObject.Lock();
}
+ if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock(): "+jawtLock); }
}
/**
- * Unlocks the AWT's global ReentrantLock.<br>
- *
+ * Unlocks the AWT's global ReentrantLock.
+ * <p>
* JAWT's native Unlock() function calls SunToolkit.awtUnlock(),
- * which just uses AWT's global ReentrantLock.<br>
+ * which just uses AWT's global ReentrantLock.
+ * </p>
+ * <p>
+ * AWT unlocking is wrapped through a recursive lock object.
+ * </p>
*/
- private static void awtUnlock() {
- if(hasSunToolkitAWTLock) {
- try {
- sunToolkitAWTUnlockMethod.invoke(null, (Object[])null);
- } catch (Exception e) {
- throw new NativeWindowException("SunToolkit.awtUnlock failed", e);
+ public static void unlockToolkit() {
+ jawtLock.validateLocked();
+ if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock(): "+jawtLock); }
+ if( 1 == jawtLock.getHoldCount() ) {
+ if(!headlessMode && !isJava2DQueueFlusherThread()) {
+ if(hasSunToolkitAWTLock) {
+ try {
+ sunToolkitAWTUnlockMethod.invoke(null, (Object[])null);
+ } catch (Exception e) {
+ throw new NativeWindowException("SunToolkit.awtUnlock failed", e);
+ }
+ } else {
+ jawtLockObject.Unlock();
+ }
}
- } else {
- jawtLockObject.Unlock();
- }
- }
-
- public static void lockToolkit() throws NativeWindowException {
- if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock()"); }
- if(!headlessMode && !isJava2DQueueFlusherThread()) {
- awtLock();
}
+ jawtLock.unlock();
}
- public static void unlockToolkit() {
- if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock()"); }
- if(!headlessMode && !isJava2DQueueFlusherThread()) {
- awtUnlock();
- }
+ public static final void validateLocked() throws RuntimeException {
+ jawtLock.validateLocked();
}
public static ToolkitLock getJAWTToolkitLock() {
return jawtToolkitLock;
}
-
+
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java
index 40d7b8032..4f12d1925 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -28,11 +28,11 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
index 0ca5cd297..8d46d805a 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,17 +29,18 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
package jogamp.nativewindow.jawt.macosx;
+import java.awt.Component;
import java.nio.Buffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -48,12 +49,13 @@ 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.MutableSurface;
import javax.media.nativewindow.util.Point;
-import com.jogamp.nativewindow.MutableGraphicsConfiguration;
import com.jogamp.nativewindow.awt.JAWTWindow;
+import jogamp.nativewindow.Debug;
+import jogamp.nativewindow.awt.AWTMisc;
import jogamp.nativewindow.jawt.JAWT;
import jogamp.nativewindow.jawt.JAWTFactory;
import jogamp.nativewindow.jawt.JAWTUtil;
@@ -62,7 +64,15 @@ import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo;
import jogamp.nativewindow.jawt.macosx.JAWT_MacOSXDrawingSurfaceInfo;
import jogamp.nativewindow.macosx.OSXUtil;
-public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable {
+public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface {
+ /** May lead to deadlock, due to AWT pos comparison .. don't enable for Applets! */
+ private static final boolean DEBUG_CALAYER_POS_CRITICAL;
+
+ static {
+ Debug.initSingleton();
+ DEBUG_CALAYER_POS_CRITICAL = Debug.isPropertyDefined("nativewindow.debug.JAWT.OSXCALayerPos", true /* jnlpAlias */);
+ }
+
public MacOSXJAWTWindow(Object comp, AbstractGraphicsConfiguration config) {
super(comp, config);
if(DEBUG) {
@@ -70,70 +80,152 @@ public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable {
}
}
+ @Override
protected void invalidateNative() {
- surfaceHandle=0;
- if(isOffscreenLayerSurfaceEnabled()) {
- if(0 != rootSurfaceLayerHandle) {
- OSXUtil.DestroyCALayer(rootSurfaceLayerHandle);
- rootSurfaceLayerHandle = 0;
- }
- if(0 != drawable) {
- OSXUtil.DestroyNSWindow(drawable);
- drawable = 0;
+ if(DEBUG) {
+ System.err.println("MacOSXJAWTWindow.invalidateNative(): osh-enabled "+isOffscreenLayerSurfaceEnabled()+
+ ", osd-set "+offscreenSurfaceDrawableSet+
+ ", osd "+toHexString(offscreenSurfaceDrawable)+
+ ", osl "+toHexString(getAttachedSurfaceLayer())+
+ ", rsl "+toHexString(rootSurfaceLayer)+
+ ", wh "+toHexString(windowHandle)+" - "+Thread.currentThread().getName());
+ }
+ offscreenSurfaceDrawable=0;
+ offscreenSurfaceDrawableSet=false;
+ if( isOffscreenLayerSurfaceEnabled() ) {
+ if(0 != windowHandle) {
+ OSXUtil.DestroyNSWindow(windowHandle);
}
+ OSXUtil.RunOnMainThread(false, new Runnable() {
+ @Override
+ public void run() {
+ if( 0 != rootSurfaceLayer ) {
+ if( 0 != jawtSurfaceLayersHandle) {
+ UnsetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer);
+ }
+ OSXUtil.DestroyCALayer(rootSurfaceLayer);
+ rootSurfaceLayer = 0;
+ }
+ jawtSurfaceLayersHandle = 0;
+ }
+ });
}
+ windowHandle=0;
}
+ @Override
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() ;
+ OSXUtil.RunOnMainThread(false, new Runnable() {
+ @Override
+ public void run() {
+ // AWT position is top-left w/ insets, where CALayer position is bottom/left from root CALayer w/o insets.
+ // Determine p0: components location on screen w/o insets.
+ // CALayer position will be determined in native code.
+ // See detailed description in {@link JAWTUtil#JAWT_OSX_CALAYER_QUIRK_LAYOUT}
+ final Point p0 = new Point();
+ final Component outterComp = getLocationOnScreenNonBlocking(p0, component);
+ final java.awt.Insets outterInsets = AWTMisc.getInsets(outterComp, true);
+ final Point p1 = (Point)p0.cloneMutable();
+ p1.translate(-outterComp.getX(), -outterComp.getY());
+ if( null != outterInsets ) {
+ p1.translate(-outterInsets.left, -outterInsets.top);
+ }
+
+ if( DEBUG_CALAYER_POS_CRITICAL ) {
+ final java.awt.Point pA0 = component.getLocationOnScreen();
+ final Point pA1 = new Point(pA0.x, pA0.y);
+ pA1.translate(-outterComp.getX(), -outterComp.getY());
+ if( null != outterInsets ) {
+ pA1.translate(-outterInsets.left, -outterInsets.top);
+ }
+ System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], pA "+pA0+" -> "+pA1+
+ ", p0 "+p0+" -> "+p1+", bounds "+bounds);
+ } else if( DEBUG ) {
+ System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds);
+ }
+ OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), JAWTUtil.getOSXCALayerQuirks());
+ } } );
}
-
- public void setSurfaceHandle(long surfaceHandle) {
- if( !isOffscreenLayerSurfaceEnabled() ) {
- throw new java.lang.UnsupportedOperationException("Not using CALAYER");
+
+ @Override
+ protected void layoutSurfaceLayerImpl(long layerHandle, boolean visible) {
+ final int caLayerQuirks = JAWTUtil.getOSXCALayerQuirks();
+ // AWT position is top-left w/ insets, where CALayer position is bottom/left from root CALayer w/o insets.
+ // Determine p0: components location on screen w/o insets.
+ // CALayer position will be determined in native code.
+ // See detailed description in {@link JAWTUtil#JAWT_OSX_CALAYER_QUIRK_LAYOUT}
+ final Point p0 = new Point();
+ final Component outterComp = getLocationOnScreenNonBlocking(p0, component);
+ final java.awt.Insets outterInsets = AWTMisc.getInsets(outterComp, true);
+ final Point p1 = (Point)p0.cloneMutable();
+ p1.translate(-outterComp.getX(), -outterComp.getY());
+ if( null != outterInsets ) {
+ p1.translate(-outterInsets.left, -outterInsets.top);
}
- if(DEBUG) {
- System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle));
+
+ if( DEBUG_CALAYER_POS_CRITICAL ) {
+ final java.awt.Point pA0 = component.getLocationOnScreen();
+ final Point pA1 = new Point(pA0.x, pA0.y);
+ pA1.translate(-outterComp.getX(), -outterComp.getY());
+ if( null != outterInsets ) {
+ pA1.translate(-outterInsets.left, -outterInsets.top);
+ }
+ System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", quirks "+caLayerQuirks+", visible "+visible+
+ ", [ins "+outterInsets+"], pA "+pA0+" -> "+pA1+
+ ", p0 "+p0+" -> "+p1+", bounds "+bounds);
+ } else if( DEBUG ) {
+ System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", quirks "+caLayerQuirks+", visible "+visible+
+ ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds);
}
- sscSet &= 0 != surfaceHandle; // reset ssc flag if NULL surfaceHandle, ie. back to JAWT
- this.surfaceHandle = surfaceHandle;
+ OSXUtil.FixCALayerLayout(rootSurfaceLayer, layerHandle, visible, p1.getX(), p1.getY(), getWidth(), getHeight(), caLayerQuirks);
}
- public void surfaceSizeChanged(int width, int height) {
- sscSet = true;
- sscWidth = width;
- sscHeight = height;
+ @Override
+ protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) {
+ OSXUtil.RunOnMainThread(false, new Runnable() {
+ @Override
+ public void run() {
+ detachNotify.run();
+ OSXUtil.RemoveCASublayer(rootSurfaceLayer, layerHandle);
+ } } );
}
- public int getWidth() {
- return sscSet ? sscWidth : super.getWidth();
+ @Override
+ public final long getWindowHandle() {
+ return windowHandle;
}
- public int getHeight() {
- return sscSet ? sscHeight: super.getHeight();
+ @Override
+ public final long getSurfaceHandle() {
+ return offscreenSurfaceDrawableSet ? offscreenSurfaceDrawable : drawable /* super.getSurfaceHandle() */ ;
+ }
+
+ @Override
+ public void setSurfaceHandle(long surfaceHandle) {
+ if( !isOffscreenLayerSurfaceEnabled() ) {
+ throw new java.lang.UnsupportedOperationException("Not using CALAYER");
+ }
+ if(DEBUG) {
+ System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): "+toHexString(surfaceHandle));
+ }
+ this.offscreenSurfaceDrawable = surfaceHandle;
+ this.offscreenSurfaceDrawableSet = true;
}
+ @Override
protected JAWT fetchJAWTImpl() throws NativeWindowException {
// use offscreen if supported and [ applet or requested ]
return JAWTUtil.getJAWT(getShallUseOffscreenLayer() || isApplet());
}
+
+ @Override
protected int lockSurfaceImpl() throws NativeWindowException {
int ret = NativeWindow.LOCK_SURFACE_NOT_READY;
- if(null == ds) {
- ds = getJAWT().GetDrawingSurface(component);
- if (ds == null) {
- // Widget not yet realized
- unlockSurfaceImpl();
- return NativeWindow.LOCK_SURFACE_NOT_READY;
- }
+ 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 ) ) ;
@@ -149,21 +241,20 @@ public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable {
if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) {
ret = NativeWindow.LOCK_SURFACE_CHANGED;
}
- if(null == dsi) {
- if (firstLock) {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- dsi = ds.GetDrawingSurfaceInfo();
- return null;
- }
- });
- } else {
- dsi = ds.GetDrawingSurfaceInfo();
- }
- if (dsi == null) {
- unlockSurfaceImpl();
- return NativeWindow.LOCK_SURFACE_NOT_READY;
- }
+ if (firstLock) {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ dsi = ds.GetDrawingSurfaceInfo();
+ return null;
+ }
+ });
+ } else {
+ dsi = ds.GetDrawingSurfaceInfo();
+ }
+ if (dsi == null) {
+ unlockSurfaceImpl();
+ return NativeWindow.LOCK_SURFACE_NOT_READY;
}
updateBounds(dsi.getBounds());
if (DEBUG && firstLock ) {
@@ -177,58 +268,83 @@ public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable {
return NativeWindow.LOCK_SURFACE_NOT_READY;
}
drawable = macosxdsi.getCocoaViewRef();
-
+
if (drawable == 0) {
unlockSurfaceImpl();
return NativeWindow.LOCK_SURFACE_NOT_READY;
} else {
+ windowHandle = OSXUtil.GetNSWindow(drawable);
ret = NativeWindow.LOCK_SUCCESS;
}
} else {
/**
* Only create a fake invisible NSWindow for the drawable handle
* to please frameworks requiring such (eg. NEWT).
- *
- * The actual surface/ca-layer shall be created/attached
- * by the upper framework (JOGL) since they require more information.
+ *
+ * The actual surface/ca-layer shall be created/attached
+ * by the upper framework (JOGL) since they require more information.
*/
+ String errMsg = null;
if(0 == drawable) {
- drawable = OSXUtil.CreateNSWindow(0, 0, getBounds().getWidth(), getBounds().getHeight());
- if(0 == drawable) {
- unlockSurfaceImpl();
- throw new NativeWindowException("Unable to created dummy NSWindow (layered case)");
+ windowHandle = OSXUtil.CreateNSWindow(0, 0, 64, 64);
+ if(0 == windowHandle) {
+ errMsg = "Unable to create dummy NSWindow (layered case)";
+ } else {
+ drawable = OSXUtil.GetNSView(windowHandle);
+ if(0 == drawable) {
+ errMsg = "Null NSView of NSWindow "+toHexString(windowHandle);
+ }
}
- // 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(null == errMsg) {
+ // Fix caps reflecting offscreen! (no GL available here ..)
+ final Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable();
+ caps.setOnscreen(false);
+ setChosenCapabilities(caps);
}
- if(!AttachJAWTSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) {
- OSXUtil.DestroyCALayer(rootSurfaceLayerHandle);
- rootSurfaceLayerHandle = 0;
- OSXUtil.DestroyNSWindow(drawable);
- drawable = 0;
- unlockSurfaceImpl();
- throw new NativeWindowException("Could not attach JAWT surfaceLayerHandle: "+this);
+ }
+ if(null == errMsg) {
+ jawtSurfaceLayersHandle = GetJAWTSurfaceLayersHandle0(dsi.getBuffer());
+ OSXUtil.RunOnMainThread(false, new Runnable() {
+ @Override
+ public void run() {
+ String errMsg = null;
+ if(0 == rootSurfaceLayer && 0 != jawtSurfaceLayersHandle) {
+ rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight());
+ if(0 == rootSurfaceLayer) {
+ errMsg = "Could not create root CALayer";
+ } else {
+ try {
+ SetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer);
+ } catch(Exception e) {
+ errMsg = "Could not set JAWT rootSurfaceLayerHandle "+toHexString(rootSurfaceLayer)+", cause: "+e.getMessage();
+ }
+ }
+ if(null != errMsg) {
+ if(0 != rootSurfaceLayer) {
+ OSXUtil.DestroyCALayer(rootSurfaceLayer);
+ rootSurfaceLayer = 0;
+ }
+ throw new NativeWindowException(errMsg+": "+MacOSXJAWTWindow.this);
+ }
+ }
+ } } );
+ }
+ if(null != errMsg) {
+ if(0 != windowHandle) {
+ OSXUtil.DestroyNSWindow(windowHandle);
+ windowHandle = 0;
}
+ drawable = 0;
+ unlockSurfaceImpl();
+ throw new NativeWindowException(errMsg+": "+this);
}
ret = NativeWindow.LOCK_SUCCESS;
}
-
+
return ret;
}
-
+
+ @Override
protected void unlockSurfaceImpl() throws NativeWindowException {
if(null!=ds) {
if (null!=dsi) {
@@ -247,7 +363,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable {
System.err.println("MaxOSXJAWTWindow: 0x"+Integer.toHexString(this.hashCode())+" - thread: "+Thread.currentThread().getName());
dumpJAWTInfo();
}
-
+
/**
* {@inheritDoc}
* <p>
@@ -257,32 +373,48 @@ public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable {
* ..
* ds = getJAWT().GetDrawingSurface(component);
* due to a SIGSEGV.
- *
+ *
* Hence we have some threading / sync issues with the native JAWT implementation.
- * </p>
+ * </p>
*/
@Override
- public Point getLocationOnScreen(Point storage) {
- return getLocationOnScreenNonBlocking(storage, component);
- }
+ public Point getLocationOnScreen(Point storage) {
+ if( null == storage ) {
+ storage = new Point();
+ }
+ getLocationOnScreenNonBlocking(storage, component);
+ return storage;
+ }
+ @Override
protected Point getLocationOnScreenNativeImpl(final int x0, final int y0) { return null; }
- private static native boolean AttachJAWTSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer);
- // private static native boolean DetachJAWTSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer);
-
+
+ private static native long GetJAWTSurfaceLayersHandle0(Buffer jawtDrawingSurfaceInfoBuffer);
+
+ /**
+ * Set the given root CALayer in the JAWT surface
+ */
+ private static native void SetJAWTRootSurfaceLayer0(long jawtSurfaceLayersHandle, long caLayer);
+
+ /**
+ * Unset the given root CALayer in the JAWT surface, passing the NIO DrawingSurfaceInfo buffer
+ */
+ private static native void UnsetJAWTRootSurfaceLayer0(long jawtSurfaceLayersHandle, long caLayer);
+
// Variables for lockSurface/unlockSurface
private JAWT_DrawingSurface ds;
private boolean dsLocked;
private JAWT_DrawingSurfaceInfo dsi;
-
+ private long jawtSurfaceLayersHandle;
+
private JAWT_MacOSXDrawingSurfaceInfo macosxdsi;
-
- private long rootSurfaceLayerHandle = 0; // attached to the JAWT_SurfaceLayer
-
- private long surfaceHandle = 0;
- private int sscWidth, sscHeight;
- private boolean sscSet = false;
-
+
+ private volatile long rootSurfaceLayer = 0; // attached to the JAWT_SurfaceLayer
+
+ private long windowHandle = 0;
+ private long offscreenSurfaceDrawable = 0;
+ private boolean offscreenSurfaceDrawableSet = false;
+
// Workaround for instance of 4796548
private boolean firstLock = true;
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java
index 74dabb67f..8b9dfabfd 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,11 +29,11 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
@@ -65,6 +65,7 @@ public class Win32SunJDKReflection {
static {
AccessController.doPrivileged(new PrivilegedAction() {
+ @Override
public Object run() {
try {
win32GraphicsDeviceClass = Class.forName("sun.awt.Win32GraphicsDevice");
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java
index 5d1d43792..54bdb34f6 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,11 +29,11 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
@@ -60,21 +60,17 @@ public class WindowsJAWTWindow extends JAWTWindow {
super(comp, config);
}
+ @Override
protected void invalidateNative() {
windowHandle = 0;
}
- protected void attachSurfaceLayerImpl(final long layerHandle) {
- throw new UnsupportedOperationException("offscreen layer not supported");
- }
- protected void detachSurfaceLayerImpl(final long layerHandle) {
- throw new UnsupportedOperationException("offscreen layer not supported");
- }
-
+ @Override
protected JAWT fetchJAWTImpl() throws NativeWindowException {
return JAWTUtil.getJAWT(false); // no offscreen
}
-
+
+ @Override
protected int lockSurfaceImpl() throws NativeWindowException {
int ret = NativeWindow.LOCK_SUCCESS;
ds = getJAWT().GetDrawingSurface(component);
@@ -117,6 +113,7 @@ public class WindowsJAWTWindow extends JAWTWindow {
return ret;
}
+ @Override
protected void unlockSurfaceImpl() throws NativeWindowException {
drawable = 0; // invalid HDC
if(null!=ds) {
@@ -138,6 +135,7 @@ public class WindowsJAWTWindow extends JAWTWindow {
return windowHandle;
}
+ @Override
protected Point getLocationOnScreenNativeImpl(int x, int y) {
return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y);
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java
index 736718de8..4599b9021 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,7 +29,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
@@ -57,19 +57,15 @@ public class X11JAWTWindow extends JAWTWindow {
super(comp, config);
}
+ @Override
protected void invalidateNative() { }
- protected void attachSurfaceLayerImpl(final long layerHandle) {
- throw new UnsupportedOperationException("offscreen layer not supported");
- }
- protected void detachSurfaceLayerImpl(final long layerHandle) {
- throw new UnsupportedOperationException("offscreen layer not supported");
- }
-
+ @Override
protected JAWT fetchJAWTImpl() throws NativeWindowException {
return JAWTUtil.getJAWT(false); // no offscreen
}
-
+
+ @Override
protected int lockSurfaceImpl() throws NativeWindowException {
int ret = NativeWindow.LOCK_SUCCESS;
ds = getJAWT().GetDrawingSurface(component);
@@ -111,6 +107,7 @@ public class X11JAWTWindow extends JAWTWindow {
return ret;
}
+ @Override
protected void unlockSurfaceImpl() throws NativeWindowException {
if(null!=ds) {
if (null!=dsi) {
@@ -126,14 +123,16 @@ public class X11JAWTWindow extends JAWTWindow {
x11dsi = null;
}
+ @Override
protected Point getLocationOnScreenNativeImpl(int x, int y) {
- return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y);
+ // surface is locked and hence the device
+ return X11Lib.GetRelativeLocation(getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y);
}
-
+
// Variables for lockSurface/unlockSurface
private JAWT_DrawingSurface ds;
private boolean dsLocked;
private JAWT_DrawingSurfaceInfo dsi;
private JAWT_X11DrawingSurfaceInfo x11dsi;
-
+
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java
index 27e0a5e50..b2c3a931b 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -29,11 +29,11 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
- *
+ *
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
@@ -65,6 +65,7 @@ public class X11SunJDKReflection {
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
try {
x11GraphicsDeviceClass = Class.forName("sun.awt.X11GraphicsDevice");
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..b71af1042
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java
@@ -0,0 +1,56 @@
+package jogamp.nativewindow.macosx;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+public class OSXDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ long nsWindow;
+
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public OSXDummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ nsWindow = 0;
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ if(0 == nsWindow && 0 == s.getSurfaceHandle()) {
+ nsWindow = OSXUtil.CreateNSWindow(0, 0, 64, 64);
+ if(0 == nsWindow) {
+ throw new NativeWindowException("Error NS window 0");
+ }
+ long nsView = OSXUtil.GetNSView(nsWindow);
+ if(0 == nsView) {
+ throw new NativeWindowException("Error NS view 0");
+ }
+ s.setSurfaceHandle(nsView);
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ if( 0 == nsWindow || 0 == s.getSurfaceHandle() ) {
+ throw new InternalError("Owns upstream surface, but no OSX view/window: "+s+", nsWindow 0x"+Long.toHexString(nsWindow));
+ }
+ OSXUtil.DestroyNSWindow(nsWindow);
+ nsWindow = 0;
+ s.setSurfaceHandle(0);
+ s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ }
+
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
index 3ca76a84a..bac07b85a 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java
@@ -28,46 +28,98 @@
package jogamp.nativewindow.macosx;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.Point;
+import com.jogamp.common.util.Function;
+import com.jogamp.common.util.FunctionTask;
+import com.jogamp.common.util.RunnableTask;
+
import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NWJNILibLoader;
+import jogamp.nativewindow.ToolkitProperties;
-public class OSXUtil {
- private static boolean isInit = false;
+public class OSXUtil implements ToolkitProperties {
+ private static boolean isInit = false;
private static final boolean DEBUG = Debug.debug("OSXUtil");
-
- public static synchronized void initSingleton(boolean firstX11ActionOnProcess) {
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static synchronized void initSingleton() {
if(!isInit) {
+ if(DEBUG) {
+ System.out.println("OSXUtil.initSingleton()");
+ }
if(!NWJNILibLoader.loadNativeWindow("macosx")) {
throw new NativeWindowException("NativeWindow MacOSX native library load error.");
}
-
+
if( !initIDs0() ) {
throw new NativeWindowException("MacOSX: Could not initialized native stub");
}
-
- if(DEBUG) {
- System.out.println("OSX.isFirstX11ActionOnProcess: "+firstX11ActionOnProcess);
- }
-
isInit = true;
}
}
- public static boolean requiresToolkitLock() {
- return false;
+ /**
+ * Called by {@link NativeWindowFactory#shutdown()}
+ * @see ToolkitProperties
+ */
+ public static void shutdown() { }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static boolean requiresToolkitLock() { return false; }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean hasThreadingIssues() { return false; }
+
+ public static boolean isNSView(long object) {
+ return 0 != object ? isNSView0(object) : false;
}
-
- public static Point GetLocationOnScreen(long windowOrView, int src_x, int src_y) {
- return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y);
+
+ public static boolean isNSWindow(long object) {
+ return 0 != object ? isNSWindow0(object) : false;
}
-
- public static long CreateNSView(int x, int y, int width, int height) {
- return CreateNSView0(x, y, width, height);
+
+ /**
+ * In case the <code>windowOrView</code> is top-level,
+ * you shall set <code>topLevel</code> to true where
+ * insets gets into account to compute the client position as follows:
+ * <pre>
+ if(topLevel) {
+ // top-level position -> client window position
+ final Insets insets = GetInsets(windowOrView);
+ los.setX(los.getX() + insets.getLeftWidth());
+ los.setY(los.getY() + insets.getTopHeight());
+ }
+ * </pre>
+ * @param windowOrView
+ * @param topLevel
+ * @param src_x
+ * @param src_y
+ * @return the client position
+ */
+ public static Point GetLocationOnScreen(long windowOrView, boolean topLevel, int src_x, int src_y) {
+ final Point los = (Point) GetLocationOnScreen0(windowOrView, src_x, src_y);
+ if(topLevel) {
+ // top-level position -> client window position
+ final Insets insets = GetInsets(windowOrView);
+ los.set(los.getX() + insets.getLeftWidth(), los.getY() + insets.getTopHeight());
+ }
+ return los;
}
- public static void DestroyNSView(long nsView) {
- DestroyNSView0(nsView);
+
+ public static Insets GetInsets(long windowOrView) {
+ return (Insets) GetInsets0(windowOrView);
}
public static long CreateNSWindow(int x, int y, int width, int height) {
@@ -76,51 +128,241 @@ public class OSXUtil {
public static void DestroyNSWindow(long nsWindow) {
DestroyNSWindow0(nsWindow);
}
-
- public static long CreateCALayer() {
- return CreateCALayer0();
+ public static long GetNSView(long nsWindow) {
+ return GetNSView0(nsWindow);
}
- public static void AddCASublayer(long rootCALayer, long subCALayer) {
+ public static long GetNSWindow(long nsView) {
+ return GetNSWindow0(nsView);
+ }
+
+ /**
+ * Create a CALayer suitable to act as a root CALayer.
+ * @see #DestroyCALayer(long)
+ * @see #AddCASublayer(long, long)
+ */
+ public static long CreateCALayer(final int width, final int height) {
+ final long l = CreateCALayer0(width, height);
+ if(DEBUG) {
+ System.err.println("OSXUtil.CreateCALayer: 0x"+Long.toHexString(l)+" - "+Thread.currentThread().getName());
+ }
+ return l;
+ }
+
+ /**
+ * Attach a sub CALayer to the root CALayer
+ * <p>
+ * Method will trigger a <code>display</code>
+ * call to the CALayer hierarchy to enforce resource creation if required, e.g. an NSOpenGLContext.
+ * </p>
+ * <p>
+ * Hence it is important that related resources are not locked <i>if</i>
+ * they will be used for creation.
+ * </p>
+ * @param caLayerQuirks TODO
+ * @see #CreateCALayer(int, int)
+ * @see #RemoveCASublayer(long, long, boolean)
+ */
+ public static void AddCASublayer(final long rootCALayer, final long subCALayer, final int x, final int y, final int width, final int height, final int caLayerQuirks) {
if(0==rootCALayer || 0==subCALayer) {
throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer));
}
- AddCASublayer0(rootCALayer, subCALayer);
+ if(DEBUG) {
+ System.err.println("OSXUtil.AttachCALayer: caLayerQuirks "+caLayerQuirks+", 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName());
+ }
+ AddCASublayer0(rootCALayer, subCALayer, x, y, width, height, caLayerQuirks);
}
- public static void RemoveCASublayer(long rootCALayer, long subCALayer) {
+
+ /**
+ * Fix root and sub CALayer position to 0/0 and size
+ * <p>
+ * If the sub CALayer implements the Objective-C NativeWindow protocol NWDedicatedSize (e.g. JOGL's MyNSOpenGLLayer),
+ * the dedicated size is passed to the layer, which propagates it appropriately.
+ * </p>
+ * <p>
+ * On OSX/Java7 our root CALayer's frame position and size gets corrupted by its NSView,
+ * hence we have created the NWDedicatedSize protocol.
+ * </p>
+ *
+ * @param rootCALayer the root surface layer, maybe null.
+ * @param subCALayer the client surface layer, maybe null.
+ * @param visible TODO
+ * @param width the expected width
+ * @param height the expected height
+ * @param caLayerQuirks TODO
+ */
+ public static void FixCALayerLayout(final long rootCALayer, final long subCALayer, final boolean visible, final int x, final int y, final int width, final int height, final int caLayerQuirks) {
+ if( 0==rootCALayer && 0==subCALayer ) {
+ return;
+ }
+ FixCALayerLayout0(rootCALayer, subCALayer, visible, x, y, width, height, caLayerQuirks);
+ }
+
+ /**
+ * Detach a sub CALayer from the root CALayer.
+ */
+ public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) {
if(0==rootCALayer || 0==subCALayer) {
throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer));
}
+ if(DEBUG) {
+ System.err.println("OSXUtil.DetachCALayer: 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName());
+ }
RemoveCASublayer0(rootCALayer, subCALayer);
}
- public static void DestroyCALayer(long caLayer) {
+
+ /**
+ * Destroy a CALayer.
+ * @see #CreateCALayer(int, int)
+ */
+ public static void DestroyCALayer(final long caLayer) {
if(0==caLayer) {
throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer));
}
- DestroyCALayer0(caLayer);
+ if(DEBUG) {
+ System.err.println("OSXUtil.DestroyCALayer: 0x"+Long.toHexString(caLayer)+" - "+Thread.currentThread().getName());
+ }
+ DestroyCALayer0(caLayer);
}
-
+
+ /**
+ * Run on OSX UI main thread.
+ * <p>
+ * 'waitUntilDone' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread.
+ * </p>
+ *
+ * @param waitUntilDone
+ * @param runnable
+ */
public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) {
- if(IsMainThread0()) {
+ if( IsMainThread0() ) {
runnable.run(); // don't leave the JVM
} else {
- RunOnMainThread0(waitUntilDone, runnable);
+ // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread,
+ // otherwise we may freeze the OSX main thread.
+ Throwable throwable = null;
+ final Object sync = new Object();
+ final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
+ synchronized(sync) {
+ RunOnMainThread0(rt);
+ if( waitUntilDone ) {
+ try {
+ sync.wait();
+ } catch (InterruptedException ie) {
+ throwable = ie;
+ }
+ if(null==throwable) {
+ throwable = rt.getThrowable();
+ }
+ if(null!=throwable) {
+ throw new RuntimeException(throwable);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Run later on ..
+ * @param onMain if true, run on main-thread, otherwise on the current OSX thread.
+ * @param runnable
+ * @param delay delay to run the runnable in milliseconds
+ */
+ public static void RunLater(boolean onMain, Runnable runnable, int delay) {
+ RunLater0(onMain, new RunnableTask( runnable, null, true, System.err ), delay);
+ }
+
+ private static Runnable _nop = new Runnable() { @Override public void run() {}; };
+
+ /** Issues a {@link #RunOnMainThread(boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done. */
+ public static void WaitUntilFinish() {
+ RunOnMainThread(true, _nop);
+ }
+
+ /**
+ * Run on OSX UI main thread.
+ * <p>
+ * 'waitUntilDone' is implemented on Java site via lock/wait on {@link FunctionTask} to not freeze OSX main thread.
+ * </p>
+ *
+ * @param waitUntilDone
+ * @param func
+ */
+ public static <R,A> R RunOnMainThread(boolean waitUntilDone, Function<R,A> func, A... args) {
+ if( IsMainThread0() ) {
+ return func.eval(args); // don't leave the JVM
+ } else {
+ // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread,
+ // otherwise we may freeze the OSX main thread.
+ Throwable throwable = null;
+ final Object sync = new Object();
+ final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
+ synchronized(sync) {
+ rt.setArgs(args);
+ RunOnMainThread0(rt);
+ if( waitUntilDone ) {
+ try {
+ sync.wait();
+ } catch (InterruptedException ie) {
+ throwable = ie;
+ }
+ if(null==throwable) {
+ throwable = rt.getThrowable();
+ }
+ if(null!=throwable) {
+ throw new RuntimeException(throwable);
+ }
+ }
+ }
+ return rt.getResult();
}
}
-
+
public static boolean IsMainThread() {
return IsMainThread0();
}
-
+
+ /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */
+ public static int GetScreenRefreshRate(int scrn_idx) {
+ return GetScreenRefreshRate0(scrn_idx);
+ }
+
+ /***
+ private static boolean isAWTEDTMainThreadInit = false;
+ private static boolean isAWTEDTMainThread;
+
+ public synchronized static boolean isAWTEDTMainThread() {
+ if(!isAWTEDTMainThreadInit) {
+ isAWTEDTMainThreadInit = true;
+ if(Platform.AWT_AVAILABLE) {
+ AWTEDTExecutor.singleton.invoke(true, new Runnable() {
+ public void run() {
+ isAWTEDTMainThread = IsMainThread();
+ System.err.println("XXX: "+Thread.currentThread().getName()+" - isAWTEDTMainThread "+isAWTEDTMainThread);
+ }
+ });
+ } else {
+ isAWTEDTMainThread = false;
+ }
+ }
+ return isAWTEDTMainThread;
+ } */
+
private static native boolean initIDs0();
+ private static native boolean isNSView0(long object);
+ private static native boolean isNSWindow0(long object);
private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y);
- private static native long CreateNSView0(int x, int y, int width, int height);
- private static native void DestroyNSView0(long nsView);
+ private static native Object GetInsets0(long windowOrView);
private static native long CreateNSWindow0(int x, int y, int width, int height);
private static native void DestroyNSWindow0(long nsWindow);
- private static native long CreateCALayer0();
- private static native void AddCASublayer0(long rootCALayer, long subCALayer);
+ private static native long GetNSView0(long nsWindow);
+ private static native long GetNSWindow0(long nsView);
+ private static native long CreateCALayer0(int width, int height);
+ private static native void AddCASublayer0(long rootCALayer, long subCALayer, int x, int y, int width, int height, int caLayerQuirks);
+ private static native void FixCALayerLayout0(long rootCALayer, long subCALayer, boolean visible, int x, int y, int width, int height, int caLayerQuirks);
private static native void RemoveCASublayer0(long rootCALayer, long subCALayer);
private static native void DestroyCALayer0(long caLayer);
- private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable);
+ private static native void RunOnMainThread0(Runnable runnable);
+ private static native void RunLater0(boolean onMain, Runnable runnable, int delay);
private static native boolean IsMainThread0();
+ private static native int GetScreenRefreshRate0(int scrn_idx);
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..e5de43c0a
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java
@@ -0,0 +1,50 @@
+package jogamp.nativewindow.windows;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+
+public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public GDIDummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ final GDISurface ms = (GDISurface)s;
+ if(0 == ms.getWindowHandle()) {
+ final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, 64, 64);
+ if(0 == windowHandle) {
+ throw new NativeWindowException("Error windowHandle 0, werr: "+GDI.GetLastError());
+ }
+ ms.setWindowHandle(windowHandle);
+ ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ final GDISurface ms = (GDISurface)s;
+ if( ms.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ if( 0 == ms.getWindowHandle() ) {
+ throw new InternalError("Owns upstream surface, but no GDI window: "+ms);
+ }
+ GDI.ShowWindow(ms.getWindowHandle(), GDI.SW_HIDE);
+ GDIUtil.DestroyDummyWindow(ms.getWindowHandle());
+ ms.setWindowHandle(0);
+ ms.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java
index bc02ac5dc..3e07b2a9e 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java
@@ -29,8 +29,13 @@
package jogamp.nativewindow.windows;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import jogamp.nativewindow.ProxySurfaceImpl;
+import jogamp.nativewindow.windows.GDI;
/**
@@ -38,25 +43,64 @@ import javax.media.nativewindow.ProxySurface;
* allowing the use of HDC via lockSurface()/unlockSurface() protocol.
* The latter will get and release the HDC.
* The size via getWidth()/getHeight() is invalid.
+ *
+ * @see ProxySurface
*/
-public class GDISurface extends ProxySurface {
+public class GDISurface extends ProxySurfaceImpl {
protected long windowHandle;
protected long surfaceHandle;
- public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle) {
- super(cfg);
- if(0 == windowHandle) {
- throw new NativeWindowException("Error hwnd 0, werr: "+GDI.GetLastError());
- }
+ /**
+ * @param cfg the {@link AbstractGraphicsConfiguration} to be used
+ * @param windowHandle the wrapped pre-existing native window handle, maybe 0 if not yet determined
+ * @param upstream the {@link UpstreamSurfaceHook} to be used
+ * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance
+ * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice},
+ * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}.
+ */
+ public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, UpstreamSurfaceHook upstream, boolean ownsDevice) {
+ super(cfg, upstream, ownsDevice);
this.windowHandle=windowHandle;
+ this.surfaceHandle=0;
+ }
+
+ @Override
+ protected void invalidateImpl() {
+ if(0 != surfaceHandle) {
+ throw new NativeWindowException("didn't release surface Handle: "+this);
+ }
+ windowHandle = 0;
+ // surfaceHandle = 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Actually the window handle (HWND), since the surfaceHandle (HDC) is derived
+ * from it at {@link #lockSurface()}.
+ * </p>
+ */
+ @Override
+ public final void setSurfaceHandle(long surfaceHandle) {
+ this.windowHandle = surfaceHandle;
}
- protected final void invalidateImpl() {
- windowHandle=0;
- surfaceHandle=0;
+ /**
+ * Sets the window handle (HWND).
+ */
+ public final void setWindowHandle(long windowHandle) {
+ this.windowHandle = windowHandle;
}
+ public final long getWindowHandle() {
+ return windowHandle;
+ }
+
+ @Override
final protected int lockSurfaceImpl() {
+ if (0 == windowHandle) {
+ throw new NativeWindowException("null window handle: "+this);
+ }
if (0 != surfaceHandle) {
throw new InternalError("surface not released");
}
@@ -70,27 +114,18 @@ public class GDISurface extends ProxySurface {
return (0 != surfaceHandle) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY;
}
+ @Override
final protected void unlockSurfaceImpl() {
- if (0 == surfaceHandle) {
- 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());
+ if (0 != surfaceHandle) {
+ if(0 == GDI.ReleaseDC(windowHandle, surfaceHandle)) {
+ throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName());
+ }
+ surfaceHandle=0;
}
- surfaceHandle=0;
}
+ @Override
final public long getSurfaceHandle() {
return surfaceHandle;
}
-
- final public String toString() {
- return "GDISurface[config "+getPrivateGraphicsConfiguration()+
- ", displayHandle 0x"+Long.toHexString(getDisplayHandle())+
- ", windowHandle 0x"+Long.toHexString(windowHandle)+
- ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+
- ", 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
index d17a1898c..720ff9bdb 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java
@@ -29,75 +29,119 @@ package jogamp.nativewindow.windows;
import javax.media.nativewindow.util.Point;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.NativeWindowFactory;
import jogamp.nativewindow.NWJNILibLoader;
import jogamp.nativewindow.Debug;
-import jogamp.nativewindow.x11.X11Util;
+import jogamp.nativewindow.ToolkitProperties;
-public class GDIUtil {
+public class GDIUtil implements ToolkitProperties {
private static final boolean DEBUG = Debug.debug("GDIUtil");
-
+
private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ;
private static RegisteredClassFactory dummyWindowClassFactory;
private static boolean isInit = false;
-
- public static synchronized void initSingleton(boolean firstX11ActionOnProcess) {
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static synchronized void initSingleton() {
if(!isInit) {
- synchronized(X11Util.class) {
+ synchronized(GDIUtil.class) {
if(!isInit) {
- isInit = true;
+ if(DEBUG) {
+ System.out.println("GDI.initSingleton()");
+ }
if(!NWJNILibLoader.loadNativeWindow("win32")) {
throw new NativeWindowException("NativeWindow Windows native library load error.");
}
-
if( !initIDs0() ) {
throw new NativeWindowException("GDI: Could not initialized native stub");
}
-
+ dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0(),
+ true /* useDummyDispatchThread */,
+ 0 /* iconSmallHandle */, 0 /* iconBigHandle */);
if(DEBUG) {
- System.out.println("GDI.isFirstX11ActionOnProcess: "+firstX11ActionOnProcess);
+ System.out.println("GDI.initSingleton() dummyWindowClassFactory "+dummyWindowClassFactory);
}
-
- dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0());
+ isInit = true;
}
}
}
}
-
+
+ /**
+ * Called by {@link NativeWindowFactory#shutdown()}
+ * @see ToolkitProperties
+ */
+ public static void shutdown() {
+ }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
public static boolean requiresToolkitLock() { return false; }
-
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean hasThreadingIssues() { return false; }
+
private static RegisteredClass dummyWindowClass = null;
private static Object dummyWindowSync = new Object();
-
+
public static long CreateDummyWindow(int x, int y, int width, int height) {
synchronized(dummyWindowSync) {
dummyWindowClass = dummyWindowClassFactory.getSharedClass();
- return CreateDummyWindow0(dummyWindowClass.getHandle(), dummyWindowClass.getName(), dummyWindowClass.getName(), x, y, width, height);
+ if(DEBUG) {
+ System.out.println("GDI.CreateDummyWindow() dummyWindowClassFactory "+dummyWindowClassFactory);
+ System.out.println("GDI.CreateDummyWindow() dummyWindowClass "+dummyWindowClass);
+ }
+ return CreateDummyWindow0(dummyWindowClass.getHInstance(), dummyWindowClass.getName(), dummyWindowClass.getHDispThreadContext(), dummyWindowClass.getName(), x, y, width, height);
}
}
-
+
public static boolean DestroyDummyWindow(long hwnd) {
boolean res;
synchronized(dummyWindowSync) {
if( null == dummyWindowClass ) {
throw new InternalError("GDI Error ("+dummyWindowClassFactory.getSharedRefCount()+"): SharedClass is null");
}
- res = GDI.DestroyWindow(hwnd);
+ res = DestroyWindow0(dummyWindowClass.getHDispThreadContext(), hwnd);
dummyWindowClassFactory.releaseSharedClass();
}
return res;
}
-
+
public static Point GetRelativeLocation(long src_win, long dest_win, int src_x, int src_y) {
return (Point) GetRelativeLocation0(src_win, dest_win, src_x, src_y);
}
-
- public static native boolean CreateWindowClass(long hInstance, String clazzName, long wndProc);
- public static native boolean DestroyWindowClass(long hInstance, String className);
-
+
+ public static boolean IsUndecorated(long win) {
+ return IsUndecorated0(win);
+ }
+
+ public static boolean IsChild(long win) {
+ return IsChild0(win);
+ }
+
+ private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI
+
+ /** Creates WNDCLASSEX instance */
+ static native boolean CreateWindowClass0(long hInstance, String clazzName, long wndProc, long iconSmallHandle, long iconBigHandle);
+ /** Destroys WNDCLASSEX instance */
+ static native boolean DestroyWindowClass0(long hInstance, String className, long dispThreadCtx);
+ static native long CreateDummyDispatchThread0();
+
private static native boolean initIDs0();
- private static native long getDummyWndProc0();
+ private static native long getDummyWndProc0();
private static native Object GetRelativeLocation0(long src_win, long dest_win, int src_x, int src_y);
-
- static native long CreateDummyWindow0(long hInstance, String className, String windowName, int x, int y, int width, int height);
+ private static native boolean IsChild0(long win);
+ private static native boolean IsUndecorated0(long win);
+
+ private static native long CreateDummyWindow0(long hInstance, String className, long dispThreadCtx, String windowName, int x, int y, int width, int height);
+ private static native boolean DestroyWindow0(long dispThreadCtx, long win);
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java
index afb3daf7c..1f6cb7c05 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java
@@ -29,17 +29,25 @@
package jogamp.nativewindow.windows;
public class RegisteredClass {
- long hInstance;
- String className;
+ private final long hInstance;
+ private final String className;
+ private final long hDDTCtx;
- RegisteredClass(long hInst, String name) {
- hInstance = hInst;
- className = name;
+ RegisteredClass(long hInst, String name, long hDispatchThreadCtx) {
+ this.hInstance = hInst;
+ this.className = name;
+ this.hDDTCtx = hDispatchThreadCtx;
}
- public final long getHandle() { return hInstance; }
+ /** Application handle, same as {@link RegisteredClassFactory#getHInstance()}. */
+ public final long getHInstance() { return hInstance; }
+
+ /** Unique Window Class Name */
public final String getName() { return className; }
+ /** Unique associated dispatch thread context for this Window Class, or 0 for none. */
+ public final long getHDispThreadContext() { return hDDTCtx; }
+
@Override
- public final String toString() { return "RegisteredClass[handle 0x"+Long.toHexString(hInstance)+", "+className+"]"; }
+ public final String toString() { return "RegisteredClass[handle 0x"+Long.toHexString(hInstance)+", "+className+", dtx 0x"+Long.toHexString(hDDTCtx)+"]"; }
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java
index 00bedfc8e..c4b4d145c 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java
@@ -29,46 +29,76 @@
package jogamp.nativewindow.windows;
import jogamp.nativewindow.Debug;
+
import java.util.ArrayList;
+
import javax.media.nativewindow.NativeWindowException;
public class RegisteredClassFactory {
- static final boolean DEBUG = Debug.debug("RegisteredClass");
- private static ArrayList<RegisteredClassFactory> registeredFactories = new ArrayList<RegisteredClassFactory>();
-
- private String classBaseName;
- private long wndProc;
+ private static final boolean DEBUG = Debug.debug("RegisteredClass");
+ private static final ArrayList<RegisteredClassFactory> registeredFactories;
+ private static final long hInstance;
+
+ static {
+ hInstance = GDI.GetApplicationHandle();
+ if( 0 == hInstance ) {
+ throw new NativeWindowException("Error: Null ModuleHandle for Application");
+ }
+ registeredFactories = new ArrayList<RegisteredClassFactory>();
+ }
+
+ private final String classBaseName;
+ private final long wndProc;
+ private final boolean useDummyDispatchThread;
+ private final long iconSmallHandle, iconBigHandle;
private RegisteredClass sharedClass = null;
private int classIter = 0;
private int sharedRefCount = 0;
private final Object sync = new Object();
+ private String toHexString(long l) { return "0x"+Long.toHexString(l); }
+
+ @Override
+ public final String toString() { return "RegisteredClassFactory[moduleHandle "+toHexString(hInstance)+", "+classBaseName+
+ ", wndProc "+toHexString(wndProc)+", useDDT "+useDummyDispatchThread+", shared[refCount "+sharedRefCount+", class "+sharedClass+"]]"; }
+
/**
- * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}.
+ * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}.
*/
public static void shutdownSharedClasses() {
synchronized(registeredFactories) {
+ if( DEBUG ) {
+ System.err.println("RegisteredClassFactory.shutdownSharedClasses: "+registeredFactories.size());
+ }
for(int j=0; j<registeredFactories.size(); j++) {
final RegisteredClassFactory rcf = registeredFactories.get(j);
synchronized(rcf.sync) {
if(null != rcf.sharedClass) {
- GDIUtil.DestroyWindowClass(rcf.sharedClass.getHandle(), rcf.sharedClass.getName());
+ GDIUtil.DestroyWindowClass0(rcf.sharedClass.getHInstance(), rcf.sharedClass.getName(), rcf.sharedClass.getHDispThreadContext());
rcf.sharedClass = null;
rcf.sharedRefCount = 0;
- rcf.classIter = 0;
+ rcf.classIter = 0;
if(DEBUG) {
- System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+" shutdownSharedClasses : "+rcf.sharedClass);
+ System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+": shutdownSharedClasses : "+rcf.sharedClass);
}
+ } else if(DEBUG) {
+ System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+": null");
}
}
}
}
}
- public RegisteredClassFactory(String classBaseName, long wndProc) {
+ /** Application handle. */
+ public static long getHInstance() { return hInstance; }
+
+ public RegisteredClassFactory(String classBaseName, long wndProc, boolean useDummyDispatchThread, long iconSmallHandle, long iconBigHandle) {
this.classBaseName = classBaseName;
this.wndProc = wndProc;
+ this.useDummyDispatchThread = useDummyDispatchThread;
+ this.iconSmallHandle = iconSmallHandle;
+ this.iconBigHandle = iconBigHandle;
synchronized(registeredFactories) {
registeredFactories.add(this);
}
@@ -80,23 +110,28 @@ public class RegisteredClassFactory {
if( null != sharedClass ) {
throw new InternalError("Error ("+sharedRefCount+"): SharedClass not null: "+sharedClass);
}
- long hInstance = GDI.GetApplicationHandle();
- if( 0 == hInstance ) {
- throw new NativeWindowException("Error: Null ModuleHandle for Application");
- }
String clazzName = null;
boolean registered = false;
- final int classIterMark = classIter - 1;
+ final int classIterMark = classIter - 1;
while ( !registered && classIterMark != classIter ) {
// Retry with next clazz name, this could happen if more than one JVM is running
clazzName = classBaseName + classIter;
classIter++;
- registered = GDIUtil.CreateWindowClass(hInstance, clazzName, wndProc);
+ registered = GDIUtil.CreateWindowClass0(hInstance, clazzName, wndProc, iconSmallHandle, iconBigHandle);
}
if( !registered ) {
throw new NativeWindowException("Error: Could not create WindowClass: "+clazzName);
}
- sharedClass = new RegisteredClass(hInstance, clazzName);
+ final long hDispatchThread;
+ if( useDummyDispatchThread ) {
+ hDispatchThread = GDIUtil.CreateDummyDispatchThread0();
+ if( 0 == hDispatchThread ) {
+ throw new NativeWindowException("Error: Could not create DDT "+clazzName);
+ }
+ } else {
+ hDispatchThread = 0;
+ }
+ sharedClass = new RegisteredClass(hInstance, clazzName, hDispatchThread);
if(DEBUG) {
System.err.println("RegisteredClassFactory getSharedClass ("+sharedRefCount+") initialized: "+sharedClass);
}
@@ -121,7 +156,7 @@ public class RegisteredClassFactory {
throw new InternalError("Error ("+sharedRefCount+"): SharedClass is null");
}
if( 0 == sharedRefCount ) {
- GDIUtil.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName());
+ GDIUtil.DestroyWindowClass0(sharedClass.getHInstance(), sharedClass.getName(), sharedClass.getHDispThreadContext());
if(DEBUG) {
System.err.println("RegisteredClassFactory releaseSharedClass ("+sharedRefCount+") released: "+sharedClass);
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java
index 0e69c738f..4f8cff8c5 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java
@@ -40,10 +40,12 @@ public class X11Capabilities extends Capabilities {
this.xVisualInfo = xVisualInfo;
}
+ @Override
public Object cloneMutable() {
return clone();
}
+ @Override
public Object clone() {
try {
return super.clone();
@@ -68,9 +70,10 @@ public class X11Capabilities extends Capabilities {
return VisualIDHolder.VID_UNDEFINED;
default:
throw new NativeWindowException("Invalid type <"+type+">");
- }
+ }
}
-
+
+ @Override
public StringBuilder toString(StringBuilder sink) {
if(null == sink) {
sink = new StringBuilder();
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java
new file mode 100644
index 000000000..2c8ef642c
--- /dev/null
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java
@@ -0,0 +1,70 @@
+package jogamp.nativewindow.x11;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+
+import jogamp.nativewindow.x11.X11Lib;
+
+import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize;
+import com.jogamp.nativewindow.x11.X11GraphicsConfiguration;
+import com.jogamp.nativewindow.x11.X11GraphicsDevice;
+import com.jogamp.nativewindow.x11.X11GraphicsScreen;
+
+public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize {
+ /**
+ * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)},
+ * not the actual dummy surface width.
+ * The latter is platform specific and small
+ * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)},
+ * not the actual dummy surface height,
+ * The latter is platform specific and small
+ */
+ public X11DummyUpstreamSurfaceHook(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public final void create(ProxySurface s) {
+ final X11GraphicsConfiguration cfg = (X11GraphicsConfiguration) s.getGraphicsConfiguration();
+ final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen();
+ final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice();
+ device.lock();
+ try {
+ if(0 == device.getHandle()) {
+ device.open();
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE );
+ }
+ if( 0 == s.getSurfaceHandle() ) {
+ final long windowHandle = X11Lib.CreateWindow(0, device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64, false, false);
+ if(0 == windowHandle) {
+ throw new NativeWindowException("Creating dummy window failed w/ "+cfg);
+ }
+ s.setSurfaceHandle(windowHandle);
+ s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ }
+ s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE);
+ } finally {
+ device.unlock();
+ }
+ }
+
+ @Override
+ public final void destroy(ProxySurface s) {
+ if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) {
+ final X11GraphicsDevice device = (X11GraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice();
+ if( 0 == s.getSurfaceHandle() ) {
+ throw new InternalError("Owns upstream surface, but no X11 window: "+s);
+ }
+ device.lock();
+ try {
+ X11Lib.DestroyWindow(device.getHandle(), s.getSurfaceHandle());
+ s.setSurfaceHandle(0);
+ s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE );
+ } finally {
+ device.unlock();
+ }
+ }
+ }
+}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java
index 070f87216..6258632cd 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -39,33 +39,40 @@ import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.GraphicsConfigurationFactory;
import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.VisualIDHolder;
import com.jogamp.nativewindow.x11.X11GraphicsConfiguration;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;
public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory {
public static void registerFactory() {
- GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, new X11GraphicsConfigurationFactory());
- }
+ GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, CapabilitiesImmutable.class, new X11GraphicsConfigurationFactory());
+ }
private X11GraphicsConfigurationFactory() {
}
-
+
+ @Override
protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl(
- CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen)
+ CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID)
throws IllegalArgumentException, NativeWindowException {
if(!(screen instanceof X11GraphicsScreen)) {
throw new NativeWindowException("Only valid X11GraphicsScreen are allowed");
}
- final X11Capabilities x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, capsChosen));
- AbstractGraphicsConfiguration res = new X11GraphicsConfiguration((X11GraphicsScreen)screen, x11CapsChosen, capsRequested, x11CapsChosen.getXVisualInfo());
+ final X11Capabilities x11CapsChosen;
+ if(VisualIDHolder.VID_UNDEFINED == nativeVisualID) {
+ x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, capsChosen));
+ } else {
+ x11CapsChosen = new X11Capabilities(getXVisualInfo(screen, nativeVisualID));
+ }
+ final AbstractGraphicsConfiguration res = new X11GraphicsConfiguration((X11GraphicsScreen)screen, x11CapsChosen, capsRequested, x11CapsChosen.getXVisualInfo());
if(DEBUG) {
- System.err.println("X11GraphicsConfigurationFactory.chooseGraphicsConfigurationImpl("+screen+","+capsChosen+"): "+res);
+ System.err.println("X11GraphicsConfigurationFactory.chooseGraphicsConfigurationImpl(visualID 0x"+Integer.toHexString(nativeVisualID)+", "+screen+","+capsChosen+"): "+res);
}
return res;
}
- public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, long visualID)
+ public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, int visualID)
{
XVisualInfo xvi_temp = XVisualInfo.create();
xvi_temp.setVisualid(visualID);
@@ -103,7 +110,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor
XVisualInfo best=null;
int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits();
for (int i = 0; vinfos!=null && i < num[0]; i++) {
- if ( best == null ||
+ if ( best == null ||
best.getDepth() < vinfos[i].getDepth() )
{
best = vinfos[i];
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
index c42bcf816..02e43791c 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -34,6 +34,7 @@
package jogamp.nativewindow.x11;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import javax.media.nativewindow.AbstractGraphicsDevice;
@@ -42,22 +43,27 @@ import javax.media.nativewindow.NativeWindowFactory;
import jogamp.nativewindow.Debug;
import jogamp.nativewindow.NWJNILibLoader;
+import jogamp.nativewindow.ToolkitProperties;
import com.jogamp.common.util.LongObjectHashMap;
+import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.nativewindow.x11.X11GraphicsDevice;
/**
* Contains a thread safe X11 utility to retrieve display connections.
*/
-public class X11Util {
- /**
+public class X11Util implements ToolkitProperties {
+ public static final boolean DEBUG = Debug.debug("X11Util");
+
+ /**
* See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515
- * <p>
+ * <p>
* It is observed that ATI X11 drivers, eg.
- * <ul>
+ * <ul>
* <li>fglrx 8.78.6,</li>
* <li>fglrx 11.08/8.881 and </li>
* <li>fglrx 11.11/8.911</li>
- * </ul>
+ * </ul>
* are quite sensitive to multiple Display connections.
* </p>
* <p>
@@ -67,113 +73,206 @@ public class X11Util {
* </p>
* <p>
* You may test this, ie just reverse the destroy order below.
- * See also native test: jogl/test/native/displayMultiple02.c
+ * See also native test: jogl/test-native/displayMultiple02.c
+ * </p>
+ * <p>
+ * Workaround is to not close them at all if driver vendor is ATI
+ * during operation.
* </p>
* <p>
- * Workaround is to not close them at all if driver vendor is ATI.
+ * With ATI X11 drivers all connections must be closed at JVM shutdown,
+ * otherwise a SIGSEGV (after JVM safepoint) will be caused.
* </p>
*/
- public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = true;
+ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG", true);
- /** Value is <code>true</code>, best 'stable' results if always using XInitThreads(). */
- public static final boolean XINITTHREADS_ALWAYS_ENABLED = true;
-
- /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */
- public static final boolean HAS_XLOCKDISPLAY_BUG = true;
-
- private static final boolean DEBUG = Debug.debug("X11Util");
- private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.getBooleanProperty("nativewindow.debug.X11Util.TraceDisplayLifecycle", true);
+ /** See {@link #ATI_HAS_XCLOSEDISPLAY_BUG}. */
+ public static final boolean HAS_XCLOSEDISPLAY_BUG = Debug.isPropertyDefined("nativewindow.debug.X11Util.HAS_XCLOSEDISPLAY_BUG", true);
+ /**
+ * See Bug 623 - https://jogamp.org/bugzilla/show_bug.cgi?id=623
+ */
+ public static final boolean ATI_HAS_MULTITHREADING_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG", true);
+
+ public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true);
+ public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true);
+ private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true);
private static String nullDisplayName = null;
- private static boolean isX11LockAvailable = false;
- private static boolean requiresX11Lock = true;
private static volatile boolean isInit = false;
- private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues
+ private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues, or GLRendererQuirks.DontCloseX11Display
+ private static boolean hasThreadingIssues = false; // ATI/AMD X11 driver issues
- private static int setX11ErrorHandlerRecCount = 0;
- private static Object setX11ErrorHandlerLock = new Object();
+ private static final Object setX11ErrorHandlerLock = new Object();
+ private static final String X11_EXTENSION_ATIFGLRXDRI = "ATIFGLRXDRI";
+ private static final String X11_EXTENSION_ATIFGLEXTENSION = "ATIFGLEXTENSION";
-
- @SuppressWarnings("unused")
- public static void initSingleton(final boolean firstX11ActionOnProcess) {
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static void initSingleton() {
if(!isInit) {
synchronized(X11Util.class) {
if(!isInit) {
isInit = true;
+ if(DEBUG) {
+ System.out.println("X11Util.initSingleton()");
+ }
if(!NWJNILibLoader.loadNativeWindow("x11")) {
throw new NativeWindowException("NativeWindow X11 native library load error.");
}
-
- 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);
+
+ final boolean isInitOK = initialize0( XERROR_STACKDUMP );
+
+ final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION;
+ final long dpy = X11Lib.XOpenDisplay(PropertyAccess.getProperty("nativewindow.x11.display.default", true));
+ if(0 != dpy) {
+ if(XSYNC_ENABLED) {
+ X11Lib.XSynchronize(dpy, true);
+ }
+ try {
+ nullDisplayName = X11Lib.XDisplayString(dpy);
+ hasX11_EXTENSION_ATIFGLRXDRI = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLRXDRI);
+ hasX11_EXTENSION_ATIFGLEXTENSION = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLEXTENSION);
+ } finally {
+ X11Lib.XCloseDisplay(dpy);
+ }
+ } else {
+ nullDisplayName = "nil";
+ hasX11_EXTENSION_ATIFGLRXDRI = false;
+ hasX11_EXTENSION_ATIFGLEXTENSION = false;
+ }
+ final boolean isATIFGLRX = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION ;
+ hasThreadingIssues = ATI_HAS_MULTITHREADING_BUG && isATIFGLRX;
+ if ( !markAllDisplaysUnclosable ) {
+ markAllDisplaysUnclosable = ( ATI_HAS_XCLOSEDISPLAY_BUG && isATIFGLRX ) || HAS_XCLOSEDISPLAY_BUG;
}
-
+
if(DEBUG) {
- System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+
- ", requiresX11Lock "+requiresX11Lock+
- ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+
- ", isX11LockAvailable "+isX11LockAvailable+
- ", X11 Display(NULL) <"+nullDisplayName+">");
+ System.err.println("X11Util.initSingleton(): OK "+isInitOK+"]"+
+ ",\n\t X11 Display(NULL) <"+nullDisplayName+">"+
+ ",\n\t XSynchronize Enabled: " + XSYNC_ENABLED+
+ ",\n\t X11_EXTENSION_ATIFGLRXDRI " + hasX11_EXTENSION_ATIFGLRXDRI+
+ ",\n\t X11_EXTENSION_ATIFGLEXTENSION " + hasX11_EXTENSION_ATIFGLEXTENSION+
+ ",\n\t requiresToolkitLock "+requiresToolkitLock()+
+ ",\n\t hasThreadingIssues "+hasThreadingIssues()+
+ ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable()
+ );
// Thread.dumpStack();
}
}
}
}
}
-
- public static synchronized boolean isNativeLockAvailable() {
- return isX11LockAvailable;
+
+ // not exactly thread safe, but good enough for our purpose,
+ // which is to tag a NamedDisplay uncloseable after creation.
+ private static Object globalLock = new Object();
+ private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name
+ private static List<NamedDisplay> openDisplayList = new ArrayList<NamedDisplay>(); // open, no close attempt
+ private static List<NamedDisplay> reusableDisplayList = new ArrayList<NamedDisplay>(); // close attempt, marked uncloseable, for reuse
+ private static List<NamedDisplay> pendingDisplayList = new ArrayList<NamedDisplay>(); // all open (close attempt or reusable) in creation order
+ private static final HashMap<String /* displayName */, Boolean> displayXineramaEnabledMap = new HashMap<String, Boolean>();
+
+ /**
+ * Cleanup resources.
+ * <p>
+ * Called by {@link NativeWindowFactory#shutdown()}
+ * </p>
+ * @see ToolkitProperties
+ */
+ public static void shutdown() {
+ if(isInit) {
+ synchronized(X11Util.class) {
+ if(isInit) {
+ final boolean isJVMShuttingDown = NativeWindowFactory.isJVMShuttingDown() ;
+ if( DEBUG ||
+ ( ( openDisplayMap.size() > 0 || reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) &&
+ ( reusableDisplayList.size() != pendingDisplayList.size() || !markAllDisplaysUnclosable )
+ ) ) {
+ System.err.println("X11Util.Display: Shutdown (JVM shutdown: "+isJVMShuttingDown+
+ ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+
+ ", reusable (open, marked uncloseable): "+reusableDisplayList.size()+
+ ", pending (open in creation order): "+pendingDisplayList.size()+
+ ")");
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ if( openDisplayList.size() > 0) {
+ X11Util.dumpOpenDisplayConnections();
+ }
+ if(DEBUG) {
+ if( reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) {
+ X11Util.dumpPendingDisplayConnections();
+ }
+ }
+ }
+
+ // Only at JVM shutdown time, since AWT impl. seems to
+ // dislike closing of X11 Display's (w/ ATI driver).
+ if( isJVMShuttingDown ) {
+ synchronized(globalLock) {
+ isInit = false;
+ closePendingDisplayConnections();
+ openDisplayList.clear();
+ reusableDisplayList.clear();
+ pendingDisplayList.clear();
+ openDisplayMap.clear();
+ displayXineramaEnabledMap.clear();
+ shutdown0();
+ }
+ }
+ }
+ }
+ }
}
- public static synchronized boolean requiresToolkitLock() {
- return requiresX11Lock;
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean requiresToolkitLock() {
+ return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock per display connection.
+ }
+
+ /**
+ * Called by {@link NativeWindowFactory#initSingleton()}
+ * @see ToolkitProperties
+ */
+ public static final boolean hasThreadingIssues() {
+ return hasThreadingIssues; // JOGL impl. may utilize special locking "somewhere"
}
public static void setX11ErrorHandler(boolean onoff, boolean quiet) {
synchronized(setX11ErrorHandlerLock) {
- if(onoff) {
- if(0==setX11ErrorHandlerRecCount) {
- setX11ErrorHandler0(true, quiet);
- }
- setX11ErrorHandlerRecCount++;
- } else {
- if(0 >= setX11ErrorHandlerRecCount) {
- throw new InternalError();
- }
- setX11ErrorHandlerRecCount--;
- if(0==setX11ErrorHandlerRecCount) {
- setX11ErrorHandler0(false, false);
- }
- }
+ setX11ErrorHandler0(onoff, quiet);
}
}
public static String getNullDisplayName() {
return nullDisplayName;
}
-
+
+ public static void markAllDisplaysUnclosable() {
+ synchronized(globalLock) {
+ markAllDisplaysUnclosable = true;
+ for(int i=0; i<openDisplayList.size(); i++) {
+ openDisplayList.get(i).setUncloseable(true);
+ }
+ for(int i=0; i<reusableDisplayList.size(); i++) {
+ reusableDisplayList.get(i).setUncloseable(true);
+ }
+ for(int i=0; i<pendingDisplayList.size(); i++) {
+ pendingDisplayList.get(i).setUncloseable(true);
+ }
+ }
+ }
+
public static boolean getMarkAllDisplaysUnclosable() {
return markAllDisplaysUnclosable;
}
- public static void setMarkAllDisplaysUnclosable(boolean v) {
- markAllDisplaysUnclosable = v;
- }
-
- private X11Util() {}
- // not exactly thread safe, but good enough for our purpose,
- // which is to tag a NamedDisplay uncloseable after creation.
- private static Object globalLock = new Object();
- private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name
- private static List<NamedDisplay> openDisplayList = new ArrayList<NamedDisplay>();
- private static List<NamedDisplay> pendingDisplayList = new ArrayList<NamedDisplay>();
+ private X11Util() {}
public static class NamedDisplay {
final String name;
@@ -201,22 +300,23 @@ public class X11Util {
}
}
+ @Override
public final int hashCode() {
return hash32;
}
-
+
+ @Override
public final boolean equals(Object obj) {
if(this == obj) { return true; }
if(obj instanceof NamedDisplay) {
- NamedDisplay n = (NamedDisplay) obj;
- return handle == n.handle;
+ return handle == ((NamedDisplay) obj).handle;
}
return false;
}
-
+
public final void addRef() { refCount++; }
public final void removeRef() { refCount--; }
-
+
public final String getName() { return name; }
public final long getHandle() { return handle; }
public final int getRefCount() { return refCount; }
@@ -226,71 +326,32 @@ public class X11Util {
public final Throwable getCreationStack() { return creationStack; }
@Override
- public Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
-
- @Override
public String toString() {
return "NamedX11Display["+name+", 0x"+Long.toHexString(handle)+", refCount "+refCount+", unCloseable "+unCloseable+"]";
}
}
- /**
- * 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) {
- 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) {
- Thread.dumpStack();
- }
- if( openDisplayList.size() > 0) {
- X11Util.dumpOpenDisplayConnections();
- }
- if( pendingDisplayList.size() > 0 ) {
- X11Util.dumpPendingDisplayConnections();
- }
- }
-
- synchronized(globalLock) {
- if(realXCloseOpenAndPendingDisplays) {
- closePendingDisplayConnections();
- openDisplayList.clear();
- pendingDisplayList.clear();
- openDisplayMap.clear();
- shutdown0();
- }
- }
- return num;
- }
-
/**
- * Closing pending Display connections in reverse order.
+ * Closing pending Display connections in original creation order, if {@link #getMarkAllDisplaysUnclosable()} is true.
*
* @return number of closed Display connections
*/
- public static int closePendingDisplayConnections() {
+ private static int closePendingDisplayConnections() {
int num=0;
synchronized(globalLock) {
- if(DEBUG) {
- System.err.println("X11Util: Closing Pending X11 Display Connections: "+pendingDisplayList.size());
- }
- for(int i=pendingDisplayList.size()-1; i>=0; i--) {
- NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i);
+ if( getMarkAllDisplaysUnclosable() ) {
+ for(int i=0; i<pendingDisplayList.size(); i++) {
+ final NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i);
+ if(DEBUG) {
+ final boolean closeAttempted = !openDisplayMap.containsKey(ndpy.getHandle());
+ System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy+" - closeAttempted "+closeAttempted);
+ }
+ XCloseDisplay(ndpy.getHandle());
+ num++;
+ }
if(DEBUG) {
- System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy);
+ System.err.println("X11Util.closePendingDisplayConnections(): Closed "+num+" pending display connections");
}
- XCloseDisplay(ndpy.getHandle());
- num++;
}
}
return num;
@@ -301,7 +362,7 @@ public class X11Util {
return openDisplayList.size();
}
}
-
+
public static void dumpOpenDisplayConnections() {
synchronized(globalLock) {
System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size());
@@ -317,7 +378,13 @@ public class X11Util {
}
}
}
-
+
+ public static int getReusableDisplayConnectionNumber() {
+ synchronized(globalLock) {
+ return reusableDisplayList.size();
+ }
+ }
+
public static int getPendingDisplayConnectionNumber() {
synchronized(globalLock) {
return pendingDisplayList.size();
@@ -326,7 +393,18 @@ public class X11Util {
public static void dumpPendingDisplayConnections() {
synchronized(globalLock) {
- System.err.println("X11Util: Pending X11 Display Connections: "+pendingDisplayList.size());
+ System.err.println("X11Util: Reusable X11 Display Connections: "+reusableDisplayList.size());
+ for(int i=0; i<reusableDisplayList.size(); i++) {
+ NamedDisplay ndpy = (NamedDisplay) reusableDisplayList.get(i);
+ System.err.println("X11Util: Reusable["+i+"]: "+ndpy);
+ if(null!=ndpy) {
+ Throwable t = ndpy.getCreationStack();
+ if(null!=t) {
+ t.printStackTrace();
+ }
+ }
+ }
+ System.err.println("X11Util: Pending X11 Display Connections (creation order): "+pendingDisplayList.size());
for(int i=0; i<pendingDisplayList.size(); i++) {
NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i);
System.err.println("X11Util: Pending["+i+"]: "+ndpy);
@@ -358,11 +436,11 @@ public class X11Util {
NamedDisplay namedDpy = null;
name = validateDisplayName(name);
boolean reused = false;
-
- synchronized(globalLock) {
- for(int i=0; i<pendingDisplayList.size(); i++) {
- if(pendingDisplayList.get(i).getName().equals(name)) {
- namedDpy = pendingDisplayList.remove(i);
+
+ synchronized(globalLock) {
+ for(int i=0; i<reusableDisplayList.size(); i++) {
+ if(reusableDisplayList.get(i).getName().equals(name)) {
+ namedDpy = reusableDisplayList.remove(i);
dpy = namedDpy.getHandle();
reused = true;
break;
@@ -376,6 +454,7 @@ public class X11Util {
// if you like to debug and synchronize X11 commands ..
// setSynchronizeDisplay(dpy, true);
namedDpy = new NamedDisplay(name, dpy);
+ pendingDisplayList.add(namedDpy);
}
namedDpy.addRef();
openDisplayMap.put(dpy, namedDpy);
@@ -392,10 +471,8 @@ public class X11Util {
}
public static void closeDisplay(long handle) {
- NamedDisplay namedDpy;
-
synchronized(globalLock) {
- namedDpy = (NamedDisplay) openDisplayMap.remove(handle);
+ final NamedDisplay namedDpy = (NamedDisplay) openDisplayMap.remove(handle);
if(null==namedDpy) {
X11Util.dumpPendingDisplayConnections();
throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped. Thread "+Thread.currentThread().getName());
@@ -404,20 +481,26 @@ public class X11Util {
X11Util.dumpPendingDisplayConnections();
throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") Mapping error: "+namedDpy+". Thread "+Thread.currentThread().getName());
}
-
+
namedDpy.removeRef();
if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); }
-
- if(!namedDpy.isUncloseable()) {
+
+ if( markAllDisplaysUnclosable ) {
+ // if set-mark 'slipped' this one .. just to be safe!
+ namedDpy.setUncloseable(true);
+ }
+ if( !namedDpy.isUncloseable() ) {
XCloseDisplay(namedDpy.getHandle());
+ pendingDisplayList.remove(namedDpy);
} else {
// for reuse
- pendingDisplayList.add(namedDpy);
+ X11Lib.XSync(namedDpy.getHandle(), true); // flush output buffer and discard all events
+ reusableDisplayList.add(namedDpy);
}
-
+
if(DEBUG) {
System.err.println("X11Util.Display: Closed (real: "+(!namedDpy.isUncloseable())+") "+namedDpy+". Thread "+Thread.currentThread().getName());
- }
+ }
}
}
@@ -427,7 +510,7 @@ 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) {
@@ -448,50 +531,60 @@ public class X11Util {
*******************************/
public static long XOpenDisplay(String arg0) {
- NativeWindowFactory.getDefaultToolkitLock().lock();
- try {
- long handle = X11Lib.XOpenDisplay(arg0);
- if(TRACE_DISPLAY_LIFECYCLE) {
- System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle));
- // Thread.dumpStack();
- }
- return handle;
- } finally {
- NativeWindowFactory.getDefaultToolkitLock().unlock();
+ long handle = X11Lib.XOpenDisplay(arg0);
+ if(XSYNC_ENABLED && 0 != handle) {
+ X11Lib.XSynchronize(handle, true);
+ }
+ if(TRACE_DISPLAY_LIFECYCLE) {
+ System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle));
+ // Thread.dumpStack();
}
+ return handle;
}
public static int XCloseDisplay(long display) {
- NativeWindowFactory.getDefaultToolkitLock().lock();
+ if(TRACE_DISPLAY_LIFECYCLE) {
+ System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display));
+ // Thread.dumpStack();
+ }
+ int res = -1;
try {
- if(TRACE_DISPLAY_LIFECYCLE) {
- System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display));
- // Thread.dumpStack();
- }
- int res = -1;
- X11Util.setX11ErrorHandler(true, DEBUG ? false : true);
- try {
- res = X11Lib.XCloseDisplay(display);
- } catch (Exception ex) {
- System.err.println("X11Util: Catched Exception:");
- ex.printStackTrace();
- } finally {
- X11Util.setX11ErrorHandler(false, false);
- }
- return res;
- } finally {
- NativeWindowFactory.getDefaultToolkitLock().unlock();
+ res = X11Lib.XCloseDisplay(display);
+ } catch (Exception ex) {
+ System.err.println("X11Util: Catched Exception:");
+ ex.printStackTrace();
}
+ return res;
}
static volatile boolean XineramaFetched = false;
static long XineramaLibHandle = 0;
static long XineramaQueryFunc = 0;
-
- public static boolean XineramaIsEnabled(long display) {
- if(0==display) {
- throw new IllegalArgumentException("Display NULL");
+
+ public static boolean XineramaIsEnabled(X11GraphicsDevice device) {
+ if(null == device) {
+ throw new IllegalArgumentException("X11 Display device is NULL");
+ }
+ device.lock();
+ try {
+ return XineramaIsEnabled(device.getHandle());
+ } finally {
+ device.unlock();
+ }
+ }
+
+ public static boolean XineramaIsEnabled(long displayHandle) {
+ if( 0 == displayHandle ) {
+ throw new IllegalArgumentException("X11 Display handle is NULL");
}
+ final String displayName = X11Lib.XDisplayString(displayHandle);
+ synchronized(displayXineramaEnabledMap) {
+ final Boolean b = displayXineramaEnabledMap.get(displayName);
+ if(null != b) {
+ return b.booleanValue();
+ }
+ }
+ final boolean res;
if(!XineramaFetched) { // volatile: ok
synchronized(X11Util.class) {
if( !XineramaFetched ) {
@@ -504,19 +597,27 @@ public class X11Util {
}
}
if(0!=XineramaQueryFunc) {
- final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, display);
+ res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, displayHandle);
+ } else {
if(DEBUG) {
- System.err.println("XineramaIsEnabled: "+res);
+ System.err.println("XineramaIsEnabled: Couldn't bind to Xinerama - lib 0x"+Long.toHexString(XineramaLibHandle)+
+ "query 0x"+Long.toHexString(XineramaQueryFunc));
}
- return res;
- } else if(DEBUG) {
- System.err.println("XineramaIsEnabled: Couldn't bind to Xinerama - lib 0x"+Long.toHexString(XineramaLibHandle)+
- "query 0x"+Long.toHexString(XineramaQueryFunc));
+ res = false;
}
- return false;
+ synchronized(displayXineramaEnabledMap) {
+ if(DEBUG) {
+ System.err.println("XineramaIsEnabled Cache: Display "+displayName+" (0x"+Long.toHexString(displayHandle)+") -> "+res);
+ }
+ displayXineramaEnabledMap.put(displayName, Boolean.valueOf(res));
+ }
+ return res;
}
-
- private static native boolean initialize0(boolean firstUIActionOnProcess);
+
+ private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI
+ private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI
+
+ private static native boolean initialize0(boolean debug);
private static native void shutdown0();
private static native void setX11ErrorHandler0(boolean onoff, boolean quiet);
}
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java
index b6bf63d44..062040232 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java
@@ -1,22 +1,22 @@
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -59,16 +59,17 @@ import jogamp.nativewindow.x11.X11Lib;
import jogamp.nativewindow.x11.X11Util;
public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory {
-
+
public static void registerFactory() {
- GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, new X11AWTGraphicsConfigurationFactory());
- }
+ GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, CapabilitiesImmutable.class, new X11AWTGraphicsConfigurationFactory());
+ }
private X11AWTGraphicsConfigurationFactory() {
}
+ @Override
protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl(
CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested,
- CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) {
+ CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) {
if (absScreen != null &&
!(absScreen instanceof AWTGraphicsScreen)) {
throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects");
@@ -77,21 +78,21 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac
absScreen = AWTGraphicsScreen.createDefault();
}
- return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen);
+ return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen, nativeVisualID);
}
-
+
public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic(
CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested,
- CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen) {
+ CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen, int nativeVisualID) {
if(DEBUG) {
System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen);
}
-
+
final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice();
final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device);
final long displayHandle;
- boolean owner = false;
+ final boolean owner;
if(0==displayHandleAWT) {
displayHandle = X11Util.openDisplay(null);
owner = true;
@@ -101,8 +102,8 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac
} else {
/**
* Using the AWT display handle works fine with NVidia.
- * However we experienced different results w/ AMD drivers,
- * some work, but some behave erratic.
+ * However we experienced different results w/ AMD drivers,
+ * some work, but some behave erratic.
* I.e. hangs in XQueryExtension(..) via X11GraphicsScreen.
*/
final String displayName = X11Lib.XDisplayString(displayHandleAWT);
@@ -112,17 +113,16 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac
System.err.println(getThreadName()+" - X11AWTGraphicsConfigurationFactory: AWT dpy "+displayName+" / "+toHexString(displayHandleAWT)+", create X11 display "+toHexString(displayHandle));
}
}
- final ToolkitLock lock = owner ?
- NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock
- NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle);
- final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner);
+ // Global JAWT lock required - No X11 resource locking due to private display connection
+ final ToolkitLock lock = NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT);
+ final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner);
final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex());
if(DEBUG) {
System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen);
}
-
- final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device);
- AbstractGraphicsConfiguration aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen);
+
+ final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device, capsChosen);
+ AbstractGraphicsConfiguration aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen, nativeVisualID);
if (aConfig == null) {
throw new NativeWindowException("Unable to choose a GraphicsConfiguration (1): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen);
}
@@ -130,7 +130,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac
System.err.println("X11AWTGraphicsConfigurationFactory: chosen config: "+aConfig);
// Thread.dumpStack();
}
-
+
//
// Match the X11/GL Visual with AWT:
// - choose a config AWT agnostic and then
@@ -138,7 +138,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac
//
// The resulting GraphicsConfiguration has to be 'forced' on the AWT native peer,
// ie. returned by GLCanvas's getGraphicsConfiguration() befor call by super.addNotify().
- //
+ //
final GraphicsConfiguration[] configs = device.getConfigurations();
int visualID = aConfig.getVisualID(VIDType.NATIVE);
if(VisualIDHolder.VID_UNDEFINED != visualID) {
@@ -160,7 +160,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac
// try again using an AWT Colormodel compatible configuration
GraphicsConfiguration gc = device.getDefaultConfiguration();
capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsChosen, gc);
- aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen);
+ aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen, nativeVisualID);
if (aConfig == null) {
throw new NativeWindowException("Unable to choose a GraphicsConfiguration (2): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen);
}