diff options
Diffstat (limited to 'src/nativewindow/classes/jogamp')
35 files changed, 2494 insertions, 965 deletions
diff --git a/src/nativewindow/classes/jogamp/nativewindow/Debug.java b/src/nativewindow/classes/jogamp/nativewindow/Debug.java index e07fd1b57..f2a45377e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/Debug.java +++ b/src/nativewindow/classes/jogamp/nativewindow/Debug.java @@ -1,44 +1,36 @@ -/* - * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. */ package jogamp.nativewindow; +import java.security.AccessController; +import java.security.PrivilegedAction; + import com.jogamp.common.util.PropertyAccess; /** Helper routines for logging and debugging. */ @@ -47,41 +39,37 @@ public class Debug extends PropertyAccess { // Some common properties private static final boolean verbose; private static final boolean debugAll; - + static { - PropertyAccess.addTrustedPrefix("nativewindow.", Debug.class); + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + PropertyAccess.addTrustedPrefix("nativewindow."); + return null; + } } ); verbose = isPropertyDefined("nativewindow.verbose", true); debugAll = isPropertyDefined("nativewindow.debug", true); if (verbose) { - Package p = Package.getPackage("javax.media.nativewindow"); + final Package p = Package.getPackage("javax.media.nativewindow"); System.err.println("NativeWindow specification version " + p.getSpecificationVersion()); System.err.println("NativeWindow implementation version " + p.getImplementationVersion()); System.err.println("NativeWindow implementation vendor " + p.getImplementationVendor()); } } - public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias) { - return PropertyAccess.isPropertyDefined(property, jnlpAlias, null); - } - - public static String getProperty(final String property, final boolean jnlpAlias) { - return PropertyAccess.getProperty(property, jnlpAlias, null); - } - - public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias) { - return PropertyAccess.getBooleanProperty(property, jnlpAlias, null); - } - - public static boolean verbose() { + /** Ensures static init block has been issues, i.e. if calling through to {@link PropertyAccess#isPropertyDefined(String, boolean)}. */ + public static final void initSingleton() {} + + public static final boolean verbose() { return verbose; } - public static boolean debugAll() { + public static final boolean debugAll() { return debugAll; } - public static boolean debug(String subcomponent) { + public static final boolean debug(final String subcomponent) { return debugAll() || isPropertyDefined("nativewindow.debug." + subcomponent, true); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java index 52e9c8308..6061c4e79 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/DefaultGraphicsConfigurationFactoryImpl.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -36,8 +36,9 @@ package jogamp.nativewindow; import javax.media.nativewindow.*; public class DefaultGraphicsConfigurationFactoryImpl extends GraphicsConfigurationFactory { + @Override protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) { + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, final CapabilitiesChooser chooser, final AbstractGraphicsScreen screen, final int nativeVisualID) { return new DefaultGraphicsConfiguration(screen, capsChosen, capsRequested); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java index 743d371b7..4f6c0d155 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/GlobalToolkitLock.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -25,52 +25,58 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package jogamp.nativewindow.jawt.x11; -import jogamp.nativewindow.jawt.*; -import jogamp.nativewindow.x11.X11Lib; -import jogamp.nativewindow.x11.X11Util; +package jogamp.nativewindow; + import javax.media.nativewindow.ToolkitLock; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; /** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. - * <br> - * This strategy should only be used if AWT is using the underlying native windowing toolkit - * in a not intrinsic thread safe manner, e.g. under X11 where no XInitThreads() call - * is issued before any other X11 usage. This is the current situation for e.g. Webstart or Applets. + * Implementing a global recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * This is the last resort for unstable driver where multiple X11 display connections + * to the same connection name are not treated thread safe within the GL/X11 driver. + * </p> */ -public class X11JAWTToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; +public class GlobalToolkitLock implements ToolkitLock { + private static final RecursiveLock globalLock = LockFactory.createRecursiveLock(); + private static GlobalToolkitLock singleton = new GlobalToolkitLock(); - public X11JAWTToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } + public static final GlobalToolkitLock getSingleton() { + return singleton; } + private GlobalToolkitLock() { } + + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } - JAWTUtil.lockToolkit(); - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); - } + globalLock.lock(); + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" GlobalToolkitLock: lock() "+toStringImpl()); } } + @Override public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } - JAWTUtil.unlockToolkit(); + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" GlobalToolkitLock: unlock() "+toStringImpl()); } + globalLock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + globalLock.validateLocked(); + } + + @Override + public final void dispose() { + // nop + } + + @Override + public String toString() { + return "GlobalToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "obj 0x"+Integer.toHexString(hashCode())+", isOwner "+globalLock.isOwner(Thread.currentThread())+", "+globalLock.toString(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java index 6c15f9a2b..8d0d04161 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java @@ -3,14 +3,14 @@ * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR @@ -20,12 +20,12 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ - + package jogamp.nativewindow; @@ -37,20 +37,17 @@ import com.jogamp.common.os.Platform; import com.jogamp.common.util.cache.TempJarCache; public class NWJNILibLoader extends JNILibLoaderBase { - - public static boolean loadNativeWindow(final String ossuffix) { - return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { - public Boolean run() { - Platform.initSingleton(); - final String libName = "nativewindow_"+ossuffix ; - if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { - // either: [jogl-all.jar, jogl-all-noawt.jar, jogl-all-mobile.jar] -> jogl-all-natives-<os.and.arch>.jar - // or: nativewindow-core.jar -> nativewindow-natives-<os.and.arch>.jar - addNativeJarLibs(new Class<?>[] { NWJNILibLoader.class }, "-all", new String[] { "-noawt", "-mobile", "-core" } ); - } - return new Boolean(loadLibrary(libName, false, NWJNILibLoader.class.getClassLoader())); - } - }).booleanValue(); - } - + public static boolean loadNativeWindow(final String ossuffix) { + return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { + @Override + public Boolean run() { + Platform.initSingleton(); + final String libName = "nativewindow_"+ossuffix ; + if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { + JNILibLoaderBase.addNativeJarLibsJoglCfg(new Class<?>[] { jogamp.nativewindow.Debug.class }); + } + return Boolean.valueOf(loadLibrary(libName, false, NWJNILibLoader.class.getClassLoader())); + } + }).booleanValue(); + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index 29564da3b..40fca0f7b 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -46,12 +46,13 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); public static ToolkitLock getNullToolkitLock() { - return nullToolkitLock; + return nullToolkitLock; } - + // This subclass of NativeWindowFactory handles the case of // NativeWindows being passed in - protected NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException { + @Override + protected NativeWindow getNativeWindowImpl(final Object winObj, final AbstractGraphicsConfiguration config) throws IllegalArgumentException { if (winObj instanceof NativeWindow) { // Use the NativeWindow directly return (NativeWindow) winObj; @@ -69,10 +70,10 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { winObj.getClass().getName() + " is unsupported; expected " + "javax.media.nativewindow.NativeWindow or "+AWTNames.ComponentClass); } - + private Constructor<?> nativeWindowConstructor = null; - private NativeWindow getAWTNativeWindow(Object winObj, AbstractGraphicsConfiguration config) { + private NativeWindow getAWTNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config) { if (nativeWindowConstructor == null) { try { final String windowingType = getNativeWindowType(true); @@ -93,16 +94,16 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { } nativeWindowConstructor = ReflectionUtil.getConstructor( - windowClassName, new Class[] { Object.class, AbstractGraphicsConfiguration.class }, - getClass().getClassLoader()); - } catch (Exception e) { + windowClassName, new Class[] { Object.class, AbstractGraphicsConfiguration.class }, + true, getClass().getClassLoader()); + } catch (final Exception e) { throw new IllegalArgumentException(e); } } try { return (NativeWindow) nativeWindowConstructor.newInstance(new Object[] { winObj, config }); - } catch (Exception ie) { + } catch (final Exception ie) { throw new IllegalArgumentException(ie); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java index 1af6bf279..bbfb585ac 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NullToolkitLock.java @@ -28,26 +28,48 @@ package jogamp.nativewindow; +import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ToolkitLock; /** - * Implementing a singleton global recursive {@link javax.media.nativewindow.ToolkitLock} - * without any locking. Since there is no locking it all, - * it is intrinsically recursive. + * Implementing a singleton global NOP {@link javax.media.nativewindow.ToolkitLock} + * without any locking. Since there is no locking it all, it is intrinsically recursive. */ public class NullToolkitLock implements ToolkitLock { - /** Singleton via {@link NativeWindowFactoryImpl#getNullToolkitLock()} */ protected NullToolkitLock() { } - + + @Override public final void lock() { if(TRACE_LOCK) { - System.err.println("NullToolkitLock.lock()"); - // Thread.dumpStack(); + System.err.println(Thread.currentThread()+" NullToolkitLock: lock() "+toStringImpl()); + // ExceptionUtils.dumpStackTrace(System.err, 1, 4); } } + @Override public final void unlock() { - if(TRACE_LOCK) { System.err.println("NullToolkitLock.unlock()"); } + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" NullToolkitLock: unlock() "+toStringImpl()); } + } + + @Override + public final void validateLocked() throws RuntimeException { + if( NativeWindowFactory.requiresToolkitLock() ) { + throw new RuntimeException("NullToolkitLock does not lock, but locking is required."); + } } + + @Override + public final void dispose() { + // nop + } + + @Override + public String toString() { + return "NullToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "obj 0x"+Integer.toHexString(hashCode()); + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java index 63f56cbae..deb685b51 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java @@ -36,17 +36,15 @@ import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.UpstreamSurfaceHook; - import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; -public abstract class ProxySurfaceImpl implements ProxySurface { +public abstract class ProxySurfaceImpl implements ProxySurface { private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - protected long displayHandle; // convenient ref of config.screen.device.handle private AbstractGraphicsConfiguration config; // control access due to delegation private UpstreamSurfaceHook upstream; private long surfaceHandle_old; - private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); private int implBitfield; private boolean upstreamSurfaceHookLifecycleEnabled; @@ -57,7 +55,7 @@ public abstract class ProxySurfaceImpl implements ProxySurface { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. */ - protected ProxySurfaceImpl(AbstractGraphicsConfiguration cfg, UpstreamSurfaceHook upstream, boolean ownsDevice) { + protected ProxySurfaceImpl(final AbstractGraphicsConfiguration cfg, final UpstreamSurfaceHook upstream, final boolean ownsDevice) { if(null == cfg) { throw new IllegalArgumentException("null AbstractGraphicsConfiguration"); } @@ -65,38 +63,41 @@ public abstract class ProxySurfaceImpl implements ProxySurface { throw new IllegalArgumentException("null UpstreamSurfaceHook"); } this.config = cfg; - this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); this.upstream = upstream; this.surfaceHandle_old = 0; this.implBitfield = 0; this.upstreamSurfaceHookLifecycleEnabled = true; if(ownsDevice) { addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); - } + } + } + + @Override + public final NativeSurface getUpstreamSurface() { + return upstream.getUpstreamSurface(); } @Override public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; } - + @Override - public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook) { + public void setUpstreamSurfaceHook(final UpstreamSurfaceHook hook) { if(null == hook) { throw new IllegalArgumentException("null UpstreamSurfaceHook"); } upstream = hook; } - + @Override - public final void enableUpstreamSurfaceHookLifecycle(boolean enable) { + public final void enableUpstreamSurfaceHookLifecycle(final boolean enable) { upstreamSurfaceHookLifecycleEnabled = enable; } - + @Override - public void createNotify() { + public void createNotify() { if(upstreamSurfaceHookLifecycleEnabled) { upstream.create(this); } - this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); this.surfaceHandle_old = 0; } @@ -111,25 +112,15 @@ public abstract class ProxySurfaceImpl implements ProxySurface { } invalidateImpl(); } - this.displayHandle = 0; this.surfaceHandle_old = 0; } - - /** + + /** * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed. - * @see #destroyNotify() + * @see #destroyNotify() */ protected void invalidateImpl() { - throw new InternalError("UpstreamSurfaceHook given, but required method not implemented."); - } - - @Override - public final long getDisplayHandle() { - return displayHandle; - } - - protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { - return config; + throw new InternalError("UpstreamSurfaceHook given, but required method not implemented."); } @Override @@ -138,10 +129,15 @@ public abstract class ProxySurfaceImpl implements ProxySurface { } @Override - public final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) { + public final long getDisplayHandle() { + return config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); + } + + @Override + public final void setGraphicsConfiguration(final AbstractGraphicsConfiguration cfg) { config = cfg; } - + @Override public final int getScreenIndex() { return getGraphicsConfiguration().getScreen().getIndex(); @@ -152,15 +148,15 @@ public abstract class ProxySurfaceImpl implements ProxySurface { @Override public abstract void setSurfaceHandle(long surfaceHandle); - + @Override - public final int getWidth() { - return upstream.getWidth(this); + public final int getSurfaceWidth() { + return upstream.getSurfaceWidth(this); } @Override - public final int getHeight() { - return upstream.getHeight(this); + public final int getSurfaceHeight() { + return upstream.getSurfaceHeight(this); } @Override @@ -169,22 +165,22 @@ public abstract class ProxySurfaceImpl implements ProxySurface { } @Override - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + public void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } @Override - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); } @Override - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + public void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); } @Override - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); } @@ -253,7 +249,8 @@ public abstract class ProxySurfaceImpl implements ProxySurface { public final Thread getSurfaceLockOwner() { return surfaceLock.getOwner(); } - + + @Override public final StringBuilder getUpstreamOptionBits(StringBuilder sink) { if(null == sink) { sink = new StringBuilder(); @@ -285,38 +282,41 @@ public abstract class ProxySurfaceImpl implements ProxySurface { sink.append(" ]"); return sink; } - + @Override public final int getUpstreamOptionBits() { return implBitfield; } - + @Override - public final boolean containsUpstreamOptionBits(int v) { + public final boolean containsUpstreamOptionBits(final int v) { return v == ( implBitfield & v ) ; } - + @Override - public final void addUpstreamOptionBits(int v) { implBitfield |= v; } - + public final void addUpstreamOptionBits(final int v) { implBitfield |= v; } + @Override - public final void clearUpstreamOptionBits(int v) { implBitfield &= ~v; } - + public final void clearUpstreamOptionBits(final int v) { implBitfield &= ~v; } + @Override public StringBuilder toString(StringBuilder sink) { if(null == sink) { sink = new StringBuilder(); } - sink.append(getUpstreamSurfaceHook()). - append(", displayHandle 0x" + Long.toHexString(getDisplayHandle())). - append(", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())). - append(", size " + getWidth() + "x" + getHeight()).append(", "); + sink.append("displayHandle 0x" + Long.toHexString(getDisplayHandle())). + append("\n, surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())). + append("\n, size " + getSurfaceWidth() + "x" + getSurfaceHeight()).append("\n, "); getUpstreamOptionBits(sink); - sink.append(", surfaceLock "+surfaceLock); + sink.append("\n, "+config). + append("\n, surfaceLock "+surfaceLock+"\n, "). + append(getUpstreamSurfaceHook()). + append("\n, upstreamSurface "+(null != getUpstreamSurface())); + // append("\n, upstreamSurface "+getUpstreamSurface()); return sink; } - + @Override public String toString() { - StringBuilder msg = new StringBuilder(); + final StringBuilder msg = new StringBuilder(); msg.append(getClass().getSimpleName()).append("[ "); toString(msg); msg.append(" ]"); diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java index 5166ef577..e4e557d36 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ResourceToolkitLock.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -25,7 +25,8 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ -package jogamp.nativewindow.x11; + +package jogamp.nativewindow; import javax.media.nativewindow.ToolkitLock; @@ -33,38 +34,53 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; /** - * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} - * utilizing {@link X11Util#XLockDisplay(long)}. - * <br> - * This strategy should not be used in case XInitThreads() is being used, - * or a higher level toolkit lock is required, ie AWT lock. + * Implementing a resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * A resource handle maybe used within a unique object + * and can be synchronized across threads via an instance of ResourceToolkitLock. + * </p> */ -public class X11ToolkitLock implements ToolkitLock { - long displayHandle; - RecursiveLock lock; +public class ResourceToolkitLock implements ToolkitLock { + public static final ResourceToolkitLock create() { + return new ResourceToolkitLock(); + } - public X11ToolkitLock(long displayHandle) { - this.displayHandle = displayHandle; - if(!X11Util.isNativeLockAvailable()) { - lock = LockFactory.createRecursiveLock(); - } + private final RecursiveLock lock; + + private ResourceToolkitLock() { + this.lock = LockFactory.createRecursiveLock(); } + @Override public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XLockDisplay(displayHandle); - } else { - lock.lock(); + lock.lock(); + if(TRACE_LOCK) { + System.err.println(Thread.currentThread()+" ResourceToolkitLock: lock() "+toStringImpl()); + // ExceptionUtils.dumpStackTrace(System.err, 1, 4); } } + @Override public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } - if(null == lock) { - X11Lib.XUnlockDisplay(displayHandle); - } else { - lock.unlock(); - } + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" ResourceToolkitLock: unlock() "+toStringImpl()); } + lock.unlock(); // implicit lock validation + } + + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); + } + + @Override + public final void dispose() { + // nop + } + + @Override + public String toString() { + return "ResourceToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java new file mode 100644 index 000000000..881fd56a6 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -0,0 +1,152 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.nativewindow; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.media.nativewindow.ToolkitLock; + +import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Implementing a shared resource based recursive {@link javax.media.nativewindow.ToolkitLock}. + * <p> + * A resource handle maybe used within many objects + * and can be synchronized across threads via an unique instance of SharedResourceToolkitLock. + * </p> + * <p> + * Implementation holds a synchronized map from handle to reference counted {@link SharedResourceToolkitLock}. + * New elements are added via {@link #get(long)} if new + * and removed via {@link #dispose()} if no more referenced. + * </p> + */ +public class SharedResourceToolkitLock implements ToolkitLock { + private static final LongObjectHashMap handle2Lock; + static { + handle2Lock = new LongObjectHashMap(); + handle2Lock.setKeyNotFoundValue(null); + } + + /** + * @return number of unclosed EGL Displays.<br> + */ + public static int shutdown(final boolean verbose) { + if(DEBUG || verbose || handle2Lock.size() > 0 ) { + System.err.println("SharedResourceToolkitLock: Shutdown (open: "+handle2Lock.size()+")"); + if(DEBUG) { + Thread.dumpStack(); + } + if( handle2Lock.size() > 0) { + dumpOpenDisplayConnections(); + } + } + return handle2Lock.size(); + } + + public static void dumpOpenDisplayConnections() { + System.err.println("SharedResourceToolkitLock: Open ResourceToolkitLock's: "+handle2Lock.size()); + int i=0; + for(final Iterator<LongObjectHashMap.Entry> iter = handle2Lock.iterator(); iter.hasNext(); i++) { + final LongObjectHashMap.Entry e = iter.next(); + System.err.println("SharedResourceToolkitLock: Open["+i+"]: "+e.value); + } + } + + public static final SharedResourceToolkitLock get(final long handle) { + SharedResourceToolkitLock res; + synchronized(handle2Lock) { + res = (SharedResourceToolkitLock) handle2Lock.get(handle); + if( null == res ) { + res = new SharedResourceToolkitLock(handle); + res.refCount.incrementAndGet(); + handle2Lock.put(handle, res); + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * NEW *: "+res); } + } else { + res.refCount.incrementAndGet(); + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.get() * EXIST *: "+res); } + } + } + return res; + } + + private final RecursiveLock lock; + private final long handle; + private final AtomicInteger refCount; + + private SharedResourceToolkitLock(final long handle) { + this.lock = LockFactory.createRecursiveLock(); + this.handle = handle; + this.refCount = new AtomicInteger(0); + } + + + @Override + public final void lock() { + lock.lock(); + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" SharedResourceToolkitLock: lock() "+toStringImpl()); } + } + + @Override + public final void unlock() { + if(TRACE_LOCK) { System.err.println(Thread.currentThread()+" SharedResourceToolkitLock: unlock() "+toStringImpl()); } + lock.unlock(); + } + + @Override + public final void validateLocked() throws RuntimeException { + lock.validateLocked(); + } + + @Override + public final void dispose() { + if(0 < refCount.get()) { // volatile OK + synchronized(handle2Lock) { + if( 0 == refCount.decrementAndGet() ) { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * REMOV *: "+this); } + handle2Lock.remove(handle); + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * DOWN *: "+this); } + } + } + } else { + if(DEBUG || TRACE_LOCK) { System.err.println("SharedResourceToolkitLock.dispose() * NULL *: "+this); } + } + } + + @Override + public String toString() { + return "SharedResourceToolkitLock["+toStringImpl()+"]"; + } + private String toStringImpl() { + return "refCount "+refCount+", handle 0x"+Long.toHexString(handle)+", obj 0x"+Integer.toHexString(hashCode())+", isOwner "+lock.isOwner(Thread.currentThread())+", "+lock.toString(); + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java new file mode 100644 index 000000000..73413cf59 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java @@ -0,0 +1,172 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ScalableSurface; + +/** + * Basic {@link ScalableSurface} utility to validate and compute pixel-scale values. + */ +public class SurfaceScaleUtils { + + private static final int[] PlatformMaxPixelScale; + private static final boolean PlatformUniformPixelScale; + private static final boolean PlatformPixelScaleSupported; + + static { + if( NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(true) ) { + PlatformMaxPixelScale = new int[] { jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE, jogamp.nativewindow.macosx.OSXUtil.MAX_PIXELSCALE }; + PlatformUniformPixelScale = true; + PlatformPixelScaleSupported = true; + } else { + PlatformMaxPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + PlatformUniformPixelScale = false; + PlatformPixelScaleSupported = false; + } + } + + /** + * Compute a new valid pixelScale to be used by {@link NativeSurface} implementations, + * based on the given request and surface's pixelScale + * + * @param result int[2] storage for result, maybe same as <code>prePixelScale</code> for in-place + * @param prePixelScale previous pixelScale + * @param reqPixelScale requested pixelScale, validated via {@link #validateReqPixelScale(int[], int, String)}. + * @param newPixelScaleRaw new raw surface pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + * @return true if pixelScale has changed, otherwise false + */ + public static boolean computePixelScale(final int[] result, final int[] prePixelScale, final int[] reqPixelScale, final int[] newPixelScaleRaw, final String DEBUG_PREFIX) { + final int newPixelScaleSafeX = 0 < newPixelScaleRaw[0] ? newPixelScaleRaw[0] : ScalableSurface.IDENTITY_PIXELSCALE; + final int newPixelScaleSafeY = 0 < newPixelScaleRaw[1] ? newPixelScaleRaw[1] : ScalableSurface.IDENTITY_PIXELSCALE; + final boolean useHiDPI = ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[0] || ScalableSurface.IDENTITY_PIXELSCALE != reqPixelScale[1]; + final int prePixelScaleX = prePixelScale[0]; + final int prePixelScaleY = prePixelScale[1]; + + if( useHiDPI ) { + result[0] = newPixelScaleSafeX; + result[1] = newPixelScaleSafeY; + } else { + result[0] = ScalableSurface.IDENTITY_PIXELSCALE; + result[1] = ScalableSurface.IDENTITY_PIXELSCALE; + } + + final boolean changed = result[0] != prePixelScaleX || result[1] != prePixelScaleY; + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".computePixelScale: useHiDPI "+useHiDPI+", ["+prePixelScaleX+"x"+prePixelScaleY+" (pre), "+ + reqPixelScale[0]+"x"+reqPixelScale[1]+" (req)] -> "+ + newPixelScaleRaw[0]+"x"+newPixelScaleRaw[1]+" (raw) -> "+ + newPixelScaleSafeX+"x"+newPixelScaleSafeY+" (safe) -> "+ + result[0]+"x"+result[1]+" (use), changed "+changed); + } + return changed; + } + + /** + * Validate the given requested pixelScale value pair, i.e. clip it to the + * limits of {@link ScalableSurface#AUTOMAX_PIXELSCALE} and {@link #getPlatformMaxPixelScale(int[])} + * <p> + * To be used by {@link ScalableSurface#setSurfaceScale(int[])} implementations. + * </p> + * + * @param result int[2] storage for result + * @param reqPixelScale requested pixelScale + * @param DEBUG_PREFIX if set, dumps debug info on stderr using this prefix + */ + public static void validateReqPixelScale(final int[] result, final int[] reqPixelScale, final String DEBUG_PREFIX) { + final int minPS = Math.min(reqPixelScale[0], reqPixelScale[1]); + if( ScalableSurface.AUTOMAX_PIXELSCALE >= minPS ) { + result[0] = ScalableSurface.AUTOMAX_PIXELSCALE; + result[1] = ScalableSurface.AUTOMAX_PIXELSCALE; + } else if( PlatformUniformPixelScale ) { + final int maxPS = Math.max(reqPixelScale[0], reqPixelScale[1]); + if( maxPS >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + result[1] = PlatformMaxPixelScale[1]; + } else { + result[0] = maxPS; + result[1] = maxPS; + } + } else { + if( reqPixelScale[0] >= PlatformMaxPixelScale[0] ) { + result[0] = PlatformMaxPixelScale[0]; + } else { + result[0] = reqPixelScale[0]; + } + if( reqPixelScale[1] >= PlatformMaxPixelScale[1] ) { + result[1] = PlatformMaxPixelScale[1]; + } else { + result[1] = reqPixelScale[1]; + } + } + if( null != DEBUG_PREFIX ) { + System.err.println(DEBUG_PREFIX+".validateReqPixelScale: ["+reqPixelScale[0]+"x"+reqPixelScale[1]+" (req), "+ + PlatformMaxPixelScale[0]+"x"+PlatformMaxPixelScale[1]+" (max)] -> "+ + result[0]+"x"+result[1]+" (valid)"); + } + } + + /** + * Replaces {@link ScalableSurface#AUTOMAX_PIXELSCALE} with {@link #getPlatformMaxPixelScale(int[])}, + * for each component. + * + * @param pixelScale int[2] value array to be tested and replaced + */ + public static void replaceAutoMaxWithPlatformMax(final int[] pixelScale) { + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[0] ) { + pixelScale[0] = PlatformMaxPixelScale[0]; + } + if( ScalableSurface.AUTOMAX_PIXELSCALE == pixelScale[1] ) { + pixelScale[1] = PlatformMaxPixelScale[1]; + } + } + + /** + * Returns the maximum platform pixelScale + */ + public static int[] getPlatformMaxPixelScale(final int[] result) { + System.arraycopy(PlatformMaxPixelScale, 0, result, 0, 2); + return result; + } + + /** + * Returns true if platform pixelScale is uniform, i.e. same scale factor for x- and y-direction, otherwise false. + */ + public static boolean isPlatformPixelScaleUniform() { + return PlatformUniformPixelScale; + } + + /** + * Returns whether the platform supports pixelScale + */ + public static boolean isPlatformPixelScaleSupported() { + return PlatformPixelScaleSupported; + } + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java index 4f68c6945..a7e136f76 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java @@ -3,14 +3,14 @@ * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. @@ -36,48 +36,56 @@ import javax.media.nativewindow.SurfaceUpdatedListener; public class SurfaceUpdatedHelper implements SurfaceUpdatedListener { private final Object surfaceUpdatedListenersLock = new Object(); private final ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); + private volatile boolean isEmpty = true; // // Management Utils - // - public int size() { return surfaceUpdatedListeners.size(); } - public SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); } - + // + public final int size() { return surfaceUpdatedListeners.size(); } + public final SurfaceUpdatedListener get(final int i) { return surfaceUpdatedListeners.get(i); } + // // Implementation of NativeSurface SurfaceUpdatedListener methods - // - - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + // + + public final void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) { addSurfaceUpdatedListener(-1, l); } - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + public final void addSurfaceUpdatedListener(int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException { if(l == null) { return; } synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size(); + if(0>index) { + index = surfaceUpdatedListeners.size(); } surfaceUpdatedListeners.add(index, l); + isEmpty = false; } } - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + public final boolean removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) { if (l == null) { - return; + return false; } synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners.remove(l); + final boolean res = surfaceUpdatedListeners.remove(l); + isEmpty = 0 == surfaceUpdatedListeners.size(); + return res; } } - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + @Override + public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) { + if( isEmpty ) { + return; + } synchronized(surfaceUpdatedListenersLock) { for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { - SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); + final SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); l.surfaceUpdated(updater, ns, when); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java new file mode 100644 index 000000000..47b3e63fa --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ToolkitProperties.java @@ -0,0 +1,47 @@ +package jogamp.nativewindow; + +import javax.media.nativewindow.NativeWindowFactory; + +/** + * Marker interface. + * <p> + * Implementation requires to provide static methods: + * <pre> + public static void initSingleton() {} + + public static void shutdown() {} + + public static boolean requiresToolkitLock() {} + + public static boolean hasThreadingIssues() {} + * </pre> + * Above static methods are invoked by {@link NativeWindowFactory#initSingleton()}, + * or {@link NativeWindowFactory#shutdown()} via reflection. + * </p> + */ +public interface ToolkitProperties { + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // void initSingleton(); + + /** + * Cleanup resources. + * <p> + * Called by {@link NativeWindowFactory#shutdown()} + * </p> + */ + // void shutdown(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean requiresToolkitLock(); + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + */ + // boolean hasThreadingIssues(); + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index e544bc61a..d3439b53f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -31,17 +31,24 @@ package jogamp.nativewindow; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.ScalableSurface; import javax.media.nativewindow.UpstreamSurfaceHook; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; -public class WrappedSurface extends ProxySurfaceImpl { - protected long surfaceHandle; +/** + * Generic Surface implementation which wraps an existing window handle. + * + * @see ProxySurface + */ +public class WrappedSurface extends ProxySurfaceImpl implements ScalableSurface { + private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; + private long surfaceHandle; /** * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information, * which is being passed to the {@link ProxySurface} instance. - * + * * @param cfg the {@link AbstractGraphicsConfiguration} to be used * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined * @param initialWidth @@ -50,11 +57,11 @@ public class WrappedSurface extends ProxySurfaceImpl { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. */ - public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, boolean ownsDevice) { + public WrappedSurface(final AbstractGraphicsConfiguration cfg, final long handle, final int initialWidth, final int initialHeight, final boolean ownsDevice) { super(cfg, new UpstreamSurfaceHookMutableSize(initialWidth, initialHeight), ownsDevice); surfaceHandle=handle; } - + /** * @param cfg the {@link AbstractGraphicsConfiguration} to be used * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined @@ -63,14 +70,16 @@ public class WrappedSurface extends ProxySurfaceImpl { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. */ - public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, UpstreamSurfaceHook upstream, boolean ownsDevice) { + public WrappedSurface(final AbstractGraphicsConfiguration cfg, final long handle, final UpstreamSurfaceHook upstream, final boolean ownsDevice) { super(cfg, upstream, ownsDevice); surfaceHandle=handle; } @Override - protected void invalidateImpl() { + protected void invalidateImpl() { surfaceHandle = 0; + hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE; + hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE; } @Override @@ -79,10 +88,10 @@ public class WrappedSurface extends ProxySurfaceImpl { } @Override - public final void setSurfaceHandle(long surfaceHandle) { + public final void setSurfaceHandle(final long surfaceHandle) { this.surfaceHandle=surfaceHandle; } - + @Override protected final int lockSurfaceImpl() { return LOCK_SUCCESS; @@ -92,4 +101,73 @@ public class WrappedSurface extends ProxySurfaceImpl { protected final void unlockSurfaceImpl() { } -} + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + pixelUnitsAndResult[0] /= hasPixelScale[0]; + pixelUnitsAndResult[1] /= hasPixelScale[1]; + return pixelUnitsAndResult; + } + + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation uses the {@link #setSurfaceScale(int[]) given pixelScale} directly. + * </p> + */ + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + windowUnitsAndResult[0] *= hasPixelScale[0]; + windowUnitsAndResult[1] *= hasPixelScale[1]; + return windowUnitsAndResult; + } + + /** + * {@inheritDoc} + * <p> + * {@link WrappedSurface}'s implementation is to simply pass the given pixelScale + * from the caller <i>down</i> to this instance without validation to be applied in the {@link #convertToPixelUnits(int[]) conversion} {@link #convertToWindowUnits(int[]) methods} <b>only</b>.<br/> + * This allows the caller to pass down knowledge about window- and pixel-unit conversion and utilize mentioned conversion methods. + * </p> + * <p> + * The given pixelScale will not impact the actual {@link #getSurfaceWidth()} and {@link #getSurfaceHeight()}, + * which is determinated by this instances {@link #getUpstreamSurface() upstream surface}. + * </p> + * <p> + * Implementation uses the default pixelScale {@link ScalableSurface#IDENTITY_PIXELSCALE} + * and resets to default values on {@link #invalidateImpl()}, i.e. {@link #destroyNotify()}. + * </p> + * <p> + * Implementation returns the given pixelScale array. + * </p> + */ + @Override + public final void setSurfaceScale(final int[] pixelScale) { + hasPixelScale[0] = pixelScale[0]; + hasPixelScale[1] = pixelScale[1]; + } + + @Override + public final int[] getRequestedSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 0, result, 0, 2); + return result; + } + + @Override + public final int[] getCurrentSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 0, result, 0, 2); + return result; + } + + @Override + public final int[] getNativeSurfaceScale(final int[] result) { + System.arraycopy(hasPixelScale, 0, result, 0, 2); + return result; + } + +}
\ No newline at end of file diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java new file mode 100644 index 000000000..fd39a3b4a --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedWindow.java @@ -0,0 +1,120 @@ +package jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.nativewindow.util.Point; + +import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; + +public class WrappedWindow extends WrappedSurface implements NativeWindow { + private final InsetsImmutable insets = new Insets(0, 0, 0, 0); + private long windowHandle; + + /** + * Utilizes a {@link UpstreamWindowHookMutableSizePos} to hold the size and position information, + * which is being passed to the {@link ProxySurface} instance. + * + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param surfaceHandle the wrapped pre-existing native surface handle, maybe 0 if not yet determined + * @param initialWinX + * @param initialWinY + * @param initialWinWidth + * @param initialWinHeight + * @param initialPixelWidth FIXME: pixel-dim == window-dim 'for now' ? + * @param initialPixelHeight FIXME: pixel-dim == window-dim 'for now' ? + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. + */ + public WrappedWindow(final AbstractGraphicsConfiguration cfg, final long surfaceHandle, + final int initialWinX, final int initialWinY, final int initialWinWidth, final int initialWinHeight, + final int initialPixelWidth, final int initialPixelHeight, + final boolean ownsDevice, final long windowHandle) { + this(cfg, surfaceHandle, + new UpstreamWindowHookMutableSizePos(initialWinX, initialWinY, initialWinWidth, initialWinHeight, + initialPixelWidth, initialPixelHeight), + ownsDevice, windowHandle); + } + + /** + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param surfaceHandle the wrapped pre-existing native surface handle, maybe 0 if not yet determined + * @param upstream the {@link UpstreamSurfaceHook} to be used + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. + */ + public WrappedWindow(final AbstractGraphicsConfiguration cfg, final long surfaceHandle, final UpstreamWindowHookMutableSizePos upstream, final boolean ownsDevice, final long windowHandle) { + super(cfg, surfaceHandle, upstream, ownsDevice); + this.windowHandle = windowHandle; + } + + @Override + protected void invalidateImpl() { + super.invalidateImpl(); + windowHandle = 0; + } + + @Override + public void destroy() { + destroyNotify(); + } + + @Override + public final NativeSurface getNativeSurface() { return this; } + + @Override + public NativeWindow getParent() { + return null; + } + + @Override + public long getWindowHandle() { + return windowHandle; + } + + @Override + public InsetsImmutable getInsets() { + return insets; + } + + @Override + public int getX() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getX(); + } + + @Override + public int getY() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getY(); + } + + @Override + public int getWidth() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getWidth(); + } + + @Override + public int getHeight() { + return ((UpstreamWindowHookMutableSizePos)getUpstreamSurfaceHook()).getHeight(); + } + + @Override + public Point getLocationOnScreen(final Point point) { + if(null!=point) { + return point; + } else { + return new Point(0, 0); + } + } + + @Override + public boolean hasFocus() { + return false; + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java index d77cd75ef..b0eda63b6 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java +++ b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java @@ -27,17 +27,31 @@ */ package jogamp.nativewindow.awt; +import java.awt.Cursor; +import java.awt.FocusTraversalPolicy; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Toolkit; import java.awt.Window; import java.awt.Component; import java.awt.Container; import java.awt.Frame; +import java.awt.image.BufferedImage; +import java.util.HashMap; + +import javax.swing.JComponent; import javax.swing.JFrame; +import javax.swing.JRootPane; import javax.swing.WindowConstants; - import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormat; +import javax.media.nativewindow.util.PixelFormatUtil; import javax.swing.MenuSelectionManager; +import jogamp.nativewindow.jawt.JAWTUtil; + public class AWTMisc { public static JFrame getJFrame(Component c) { @@ -69,13 +83,157 @@ public class AWTMisc { } /** + * Return insets of the component w/o traversing up to parent, + * i.e. trying Window and JComponent. + * <p> + * Exception is JRootPane. + * Return it's parent's Window component's insets if available, + * otherwise return JRootPane's insets.<br> + * This is due to <i>experience</i> that <i>some</i> JRootPane's + * do not expose valid insets value. + * </p> + * @param topLevelOnly if true only returns insets of top-level components, i.e. Window and JRootPanel, + * otherwise for JComponent as well. + */ + public static Insets getInsets(final Component c, final boolean topLevelOnly) { + if( c instanceof Window ) { + return ((Window)c).getInsets(); + } + if( c instanceof JRootPane ) { + final Window w = getWindow(c); + if( null != w ) { + return w.getInsets(); + } + return ((JRootPane)c).getInsets(); + } + if( !topLevelOnly && c instanceof JComponent ) { + return ((JComponent)c).getInsets(); + } + return null; + } + + public static interface ComponentAction { + /** + * @param c the component to perform the action on + */ + public void run(Component c); + } + + public static int performAction(final Container c, final Class<?> cType, final ComponentAction action) { + int count = 0; + final int cc = c.getComponentCount(); + for(int i=0; i<cc; i++) { + final Component e = c.getComponent(i); + if( e instanceof Container ) { + count += performAction((Container)e, cType, action); + } else if( cType.isInstance(e) ) { + action.run(e); + count++; + } + } + // we come at last .. + if( cType.isInstance(c) ) { + action.run(c); + count++; + } + return count; + } + + /** + * Traverse to the next forward or backward component using the + * container's FocusTraversalPolicy. + * + * @param comp the assumed current focuse component + * @param forward if true, returns the next focus component, otherwise the previous one. + * @return + */ + public static Component getNextFocus(Component comp, final boolean forward) { + Container focusContainer = comp.getFocusCycleRootAncestor(); + while ( focusContainer != null && + ( !focusContainer.isShowing() || !focusContainer.isFocusable() || !focusContainer.isEnabled() ) ) + { + comp = focusContainer; + focusContainer = comp.getFocusCycleRootAncestor(); + } + Component next = null; + if (focusContainer != null) { + final FocusTraversalPolicy policy = focusContainer.getFocusTraversalPolicy(); + next = forward ? policy.getComponentAfter(focusContainer, comp) : policy.getComponentBefore(focusContainer, comp); + if (next == null) { + next = policy.getDefaultComponent(focusContainer); + } + } + return next; + } + + /** * Issue this when your non AWT toolkit gains focus to clear AWT menu path */ public static void clearAWTMenus() { MenuSelectionManager.defaultManager().clearSelectedPath(); } - public static WindowClosingProtocol.WindowClosingMode AWT2NWClosingOperation(int awtClosingOperation) { + static final HashMap<Integer, Cursor> cursorMap = new HashMap<Integer, Cursor>(); + static final Cursor nulCursor; + static { + Cursor _nulCursor = null; + if( !JAWTUtil.isHeadlessMode() ) { + try { + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + final BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR); + _nulCursor = toolkit.createCustomCursor(img, new Point(0,0), "nullCursor"); + } catch (final Exception he) { + if( JAWTUtil.DEBUG ) { + System.err.println("Caught exception: "+he.getMessage()); + he.printStackTrace(); + } + } + } + nulCursor = _nulCursor; + } + + public static synchronized Cursor getNullCursor() { return nulCursor; } + + public static synchronized Cursor getCursor(final PixelRectangle pixelrect, final Point hotSpot) { + // 31 * x == (x << 5) - x + int hash = 31 + pixelrect.hashCode(); + hash = ((hash << 5) - hash) + hotSpot.hashCode(); + final Integer key = Integer.valueOf(hash); + + Cursor cursor = cursorMap.get(key); + if( null == cursor ) { + cursor = createCursor(pixelrect, hotSpot); + cursorMap.put(key, cursor); + } + return cursor; + } + private static synchronized Cursor createCursor(final PixelRectangle pixelrect, final Point hotSpot) { + final int width = pixelrect.getSize().getWidth(); + final int height = pixelrect.getSize().getHeight(); + final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // PixelFormat.BGRA8888 + final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() { + public void store(final int x, final int y, final int pixel) { + img.setRGB(x, y, pixel); + } + @Override + public final PixelFormat getPixelformat() { + return PixelFormat.BGRA8888; + } + @Override + public int getStride() { + return width*4; + } + @Override + public final boolean isGLOriented() { + return false; + } + }; + PixelFormatUtil.convert32(imgSink, pixelrect); + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + return toolkit.createCustomCursor(img, hotSpot, pixelrect.toString()); + } + + public static WindowClosingProtocol.WindowClosingMode AWT2NWClosingOperation(final int awtClosingOperation) { switch (awtClosingOperation) { case WindowConstants.DISPOSE_ON_CLOSE: case WindowConstants.EXIT_ON_CLOSE: @@ -88,7 +246,7 @@ public class AWTMisc { } } - public static WindowClosingProtocol.WindowClosingMode getNWClosingOperation(Component c) { + public static WindowClosingProtocol.WindowClosingMode getNWClosingOperation(final Component c) { final JFrame jf = getJFrame(c); final int op = (null != jf) ? jf.getDefaultCloseOperation() : WindowConstants.DO_NOTHING_ON_CLOSE ; return AWT2NWClosingOperation(op); diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java index f579da217..8aaffbd84 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -28,11 +28,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -47,15 +47,16 @@ import java.awt.Toolkit; import java.security.AccessController; import java.security.PrivilegedAction; -public class JAWTJNILibLoader extends NWJNILibLoader { +public class JAWTJNILibLoader extends NWJNILibLoader { static { AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { // Make sure that awt.dll is loaded before loading jawt.dll. Otherwise // a Dialog with "awt.dll not found" might pop up. // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4481947. Toolkit.getDefaultToolkit(); - + // Must pre-load JAWT on all non-Mac platforms to // ensure references from jogl_awt shared object // will succeed since JAWT shared object isn't in @@ -63,7 +64,7 @@ public class JAWTJNILibLoader extends NWJNILibLoader { if ( NativeWindowFactory.TYPE_MACOSX != NativeWindowFactory.getNativeWindowType(false) ) { try { loadLibrary("jawt", null, true, JAWTJNILibLoader.class.getClassLoader()); - } catch (Throwable t) { + } catch (final Throwable t) { // It might be ok .. if it's already loaded if(DEBUG) { t.printStackTrace(); @@ -74,9 +75,9 @@ public class JAWTJNILibLoader extends NWJNILibLoader { } }); } - + public static void initSingleton() { - // just exist to ensure static init has been run + // just exist to ensure static init has been run } - + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index f1e8a786a..231a89c26 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,7 +29,7 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. @@ -38,6 +38,8 @@ package jogamp.nativewindow.jawt; import java.awt.EventQueue; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.lang.reflect.InvocationTargetException; @@ -51,23 +53,30 @@ import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ToolkitLock; +import jogamp.common.os.PlatformPropsImpl; import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NWJNILibLoader; import com.jogamp.common.os.Platform; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.VersionNumber; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; public class JAWTUtil { public static final boolean DEBUG = Debug.debug("JAWT"); + private static final boolean SKIP_AWT_HIDPI; + /** OSX JAWT version option to use CALayer */ public static final int JAWT_MACOSX_USE_CALAYER = 0x80000000; - + /** OSX JAWT CALayer availability on Mac OS X >= 10.6 Update 4 (recommended) */ public static final VersionNumber JAWT_MacOSXCALayerMinVersion = new VersionNumber(10,6,4); - + /** OSX JAWT CALayer required with Java >= 1.7.0 (implies OS X >= 10.7 */ - public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = new VersionNumber(1,7,0); - + public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = Platform.Version17; + // See whether we're running in headless mode private static final boolean headlessMode; private static final JAWT jawtLockObject; @@ -80,75 +89,196 @@ public class JAWTUtil { private static final Method sunToolkitAWTUnlockMethod; private static final boolean hasSunToolkitAWTLock; + private static final RecursiveLock jawtLock; private static final ToolkitLock jawtToolkitLock; + private static final Method getScaleFactorMethod; + private static class PrivilegedDataBlob1 { PrivilegedDataBlob1() { ok = false; - } - Method sunToolkitAWTLockMethod; - Method sunToolkitAWTUnlockMethod; + } + Method sunToolkitAWTLockMethod; + Method sunToolkitAWTUnlockMethod; + Method getScaleFactorMethod; boolean ok; } - + /** * Returns true if this platform's JAWT implementation supports offscreen layer. */ public static boolean isOffscreenLayerSupported() { - return Platform.OS_TYPE == Platform.OSType.MACOS && - Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0; + return PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && + PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0; } - + /** * Returns true if this platform's JAWT implementation requires using offscreen layer. */ public static boolean isOffscreenLayerRequired() { - return Platform.OS_TYPE == Platform.OSType.MACOS && - Platform.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0; + return PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && + PlatformPropsImpl.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0; } - + + /** + * CALayer size needs to be set using the AWT component size. + * <p> + * AWT's super-calayer, i.e. the AWT's own component CALayer, + * does not layout our root-calayer in respect to this component's + * position and size, at least when resizing programmatically. + * </p> + * <p> + * As of today, this flag is enabled for all known AWT versions. + * </p> + * <p> + * Sync w/ NativeWindowProtocols.h + * </p> + */ + public static final int JAWT_OSX_CALAYER_QUIRK_SIZE = 1 << 0; + + /** + * CALayer position needs to be set to zero. + * <p> + * AWT's super-calayer, i.e. the AWT's own component CALayer, + * has a broken layout and needs it's sub-layers to be located at position 0/0. + * </p> + * <p> + * See <code>http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172187</code>. + * </p> + * <p> + * Further more a re-layout seems to be required in this case, + * i.e. a programmatic forced resize +1 and it's inverted resize -1. + * </p> + * <p> + * This flag is enabled w/ AWT < 1.7.0_40. + * </p> + * <p> + * Sync w/ NativeWindowProtocols.h + * </p> + */ + public static final int JAWT_OSX_CALAYER_QUIRK_POSITION = 1 << 1; + + /** + * CALayer position needs to be derived from AWT position + * in relation to super CALayer. + * <p> + * AWT's super-calayer, i.e. the AWT top-container's CALayer, + * does not layout our root-calayer in respect to this component's + * position and size, at least when resizing programmatically. + * </p> + * <p> + * CALayer position has origin 0/0 at bottom/left, + * where AWT component has origin 0/0 at top/left. + * </p> + * <p> + * The super-calayer bounds exclude the frame's heavyweight border/insets. + * </p> + * <p> + * The super-calayer lies within the AWT top-container client space (content). + * </p> + * <p> + * Component's location in super-calayer: + * <pre> + p0 = c.locationOnScreen(); + p0 -= c.getOutterComp.getPos(); + p0 -= c.getOutterComp.getInsets(); + * </pre> + * Where 'locationOnScreen()' is: + * <pre> + p0 = 0/0; + while( null != c ) { + p0 += c.getPos(); + } + * </pre> + * </p> + * <p> + * This flags also sets {@link #JAWT_OSX_CALAYER_QUIRK_SIZE}, + * i.e. they are related. + * </p> + * <p> + * As of today, this flag is enabled for w/ AWT >= 1.7.0_40. + * </p> + * <p> + * Sync w/ NativeWindowProtocols.h + * </p> + */ + public static final int JAWT_OSX_CALAYER_QUIRK_LAYOUT = 1 << 2; + + /** + * Returns bitfield of required JAWT OSX CALayer quirks to mediate AWT impl. bugs. + * <p> + * Returns zero, if platform is not {@link Platform.OSType#MACOS} + * or not supporting CALayer, i.e. OSX < 10.6.4. + * </p> + * <p> + * Otherwise includes + * <ul> + * <li>{@link #JAWT_OSX_CALAYER_QUIRK_SIZE} (always)</li> + * <li>{@link #JAWT_OSX_CALAYER_QUIRK_POSITION} if JVM < 1.7.0_40</li> + * <li>{@link #JAWT_OSX_CALAYER_QUIRK_LAYOUT} if JVM >= 1.7.0_40</li> + * </ul> + * </p> + */ + public static int getOSXCALayerQuirks() { + int res = 0; + if( PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && + PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0 ) { + + /** Knowing impl. all expose the SIZE bug */ + res |= JAWT_OSX_CALAYER_QUIRK_SIZE; + + final int c = PlatformPropsImpl.JAVA_VERSION_NUMBER.compareTo(PlatformPropsImpl.Version17); + if( c < 0 || c == 0 && PlatformPropsImpl.JAVA_VERSION_UPDATE < 40 ) { + res |= JAWT_OSX_CALAYER_QUIRK_POSITION; + } else { + res |= JAWT_OSX_CALAYER_QUIRK_LAYOUT; + } + } + return res; + } + /** * @param useOffscreenLayerIfAvailable * @return */ - public static JAWT getJAWT(boolean useOffscreenLayerIfAvailable) { - final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; - JAWT jawt = JAWT.create(); - + public static JAWT getJAWT(final boolean useOffscreenLayerIfAvailable) { + final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; + final JAWT jawt = JAWT.create(); + // default queries boolean tryOffscreenLayer; boolean tryOnscreen; int jawt_version_flags_offscreen = jawt_version_flags; - + if(isOffscreenLayerRequired()) { - if(Platform.OS_TYPE == Platform.OSType.MACOS) { - if(Platform.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0) { + if(PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) { + if(PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0) { jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER; tryOffscreenLayer = true; tryOnscreen = false; } else { - throw new RuntimeException("OSX: Invalid version of Java ("+Platform.JAVA_VERSION_NUMBER+") / OS X ("+Platform.OS_VERSION_NUMBER+")"); + throw new RuntimeException("OSX: Invalid version of Java ("+PlatformPropsImpl.JAVA_VERSION_NUMBER+") / OS X ("+PlatformPropsImpl.OS_VERSION_NUMBER+")"); } } else { - throw new InternalError("offscreen required, but n/a for: "+Platform.OS_TYPE); + throw new InternalError("offscreen required, but n/a for: "+PlatformPropsImpl.OS_TYPE); } } else if(useOffscreenLayerIfAvailable && isOffscreenLayerSupported()) { - if(Platform.OS_TYPE == Platform.OSType.MACOS) { + if(PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) { jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER; tryOffscreenLayer = true; tryOnscreen = true; } else { - throw new InternalError("offscreen requested and supported, but n/a for: "+Platform.OS_TYPE); + throw new InternalError("offscreen requested and supported, but n/a for: "+PlatformPropsImpl.OS_TYPE); } } else { tryOffscreenLayer = false; tryOnscreen = true; - } + } if(DEBUG) { System.err.println("JAWTUtil.getJAWT(tryOffscreenLayer "+tryOffscreenLayer+", tryOnscreen "+tryOnscreen+")"); } - - StringBuilder errsb = new StringBuilder(); + + final StringBuilder errsb = new StringBuilder(); if(tryOffscreenLayer) { errsb.append("Offscreen 0x").append(Integer.toHexString(jawt_version_flags_offscreen)); if( JAWT.getJAWT(jawt, jawt_version_flags_offscreen) ) { @@ -162,82 +292,118 @@ public class JAWTUtil { errsb.append("Onscreen 0x").append(Integer.toHexString(jawt_version_flags)); if( JAWT.getJAWT(jawt, jawt_version_flags) ) { return jawt; - } + } } throw new RuntimeException("Unable to initialize JAWT, trials: "+errsb.toString()); } - - public static boolean isJAWTUsingOffscreenLayer(JAWT jawt) { + + public static boolean isJAWTUsingOffscreenLayer(final JAWT jawt) { return 0 != ( jawt.getCachedVersion() & JAWTUtil.JAWT_MACOSX_USE_CALAYER ); } - + static { + SKIP_AWT_HIDPI = PropertyAccess.isPropertyDefined("nativewindow.awt.nohidpi", true); + if(DEBUG) { - System.err.println("JAWTUtil initialization (JAWT/JNI/..."); + System.err.println("JAWTUtil initialization (JAWT/JNI/...); SKIP_AWT_HIDPI "+SKIP_AWT_HIDPI); // Thread.dumpStack(); } - JAWTJNILibLoader.initSingleton(); - if(!JAWTJNILibLoader.loadNativeWindow("awt")) { - throw new NativeWindowException("NativeWindow AWT native library load error."); - } headlessMode = GraphicsEnvironment.isHeadless(); - boolean ok = false; - Class<?> jC = null; - Method m = null; - if (!headlessMode) { + + if( headlessMode ) { + // Headless case + jawtLockObject = null; + isQueueFlusherThread = null; + j2dExist = false; + sunToolkitAWTLockMethod = null; + sunToolkitAWTUnlockMethod = null; + hasSunToolkitAWTLock = false; + // hasSunToolkitAWTLock = false; + getScaleFactorMethod = null; + } else { + // Non-headless case + JAWTJNILibLoader.initSingleton(); // load libjawt.so + if(!NWJNILibLoader.loadNativeWindow("awt")) { // load libnativewindow_awt.so + throw new NativeWindowException("NativeWindow AWT native library load error."); + } jawtLockObject = getJAWT(false); // don't care for offscreen layer here + + boolean j2dExistTmp = false; + Class<?> java2DClass = null; + Method isQueueFlusherThreadTmp = null; try { - jC = Class.forName("jogamp.opengl.awt.Java2D"); - m = jC.getMethod("isQueueFlusherThread", (Class[])null); - ok = true; - } catch (Exception e) { + java2DClass = Class.forName("jogamp.opengl.awt.Java2D"); + isQueueFlusherThreadTmp = java2DClass.getMethod("isQueueFlusherThread", (Class[])null); + j2dExistTmp = true; + } catch (final Exception e) { } - } else { - jawtLockObject = null; // headless ! - } - isQueueFlusherThread = m; - j2dExist = ok; - - PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); - try { - final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); - d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); - d.sunToolkitAWTLockMethod.setAccessible(true); - d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); - d.sunToolkitAWTUnlockMethod.setAccessible(true); - d.ok=true; - } catch (Exception e) { - // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 + isQueueFlusherThread = isQueueFlusherThreadTmp; + j2dExist = j2dExistTmp; + + final PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + final PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); + try { + final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); + d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); + d.sunToolkitAWTLockMethod.setAccessible(true); + d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); + d.sunToolkitAWTUnlockMethod.setAccessible(true); + d.ok=true; + } catch (final Exception e) { + // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 + } + try { + final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + d.getScaleFactorMethod = gd.getClass().getDeclaredMethod("getScaleFactor"); + d.getScaleFactorMethod.setAccessible(true); + } catch (final Throwable t) {} + return d; + } + }); + sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod; + sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod; + getScaleFactorMethod = pdb1.getScaleFactorMethod; + + boolean _hasSunToolkitAWTLock = false; + if ( pdb1.ok ) { + try { + sunToolkitAWTLockMethod.invoke(null, (Object[])null); + sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); + _hasSunToolkitAWTLock = true; + } catch (final Exception e) { } - return d; - } - }); - sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod; - sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod; - - boolean _hasSunToolkitAWTLock = false; - if ( pdb1.ok ) { - try { - sunToolkitAWTLockMethod.invoke(null, (Object[])null); - sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); - _hasSunToolkitAWTLock = true; - } catch (Exception e) { } + hasSunToolkitAWTLock = _hasSunToolkitAWTLock; + // hasSunToolkitAWTLock = false; } - hasSunToolkitAWTLock = _hasSunToolkitAWTLock; - // hasSunToolkitAWTLock = false; + + jawtLock = LockFactory.createRecursiveLock(); jawtToolkitLock = new ToolkitLock() { + @Override public final void lock() { JAWTUtil.lockToolkit(); - } + } + @Override public final void unlock() { JAWTUtil.unlockToolkit(); } - }; + @Override + public final void validateLocked() throws RuntimeException { + JAWTUtil.validateLocked(); + } + @Override + public final void dispose() { + // nop + } + @Override + public String toString() { + return "JAWTToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+jawtLock.isOwner(Thread.currentThread())+", "+jawtLock+"]"; + } + }; // trigger native AWT toolkit / properties initialization Map<?,?> desktophints = null; @@ -247,8 +413,9 @@ public class JAWTUtil { } else { final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1); EventQueue.invokeAndWait(new Runnable() { + @Override public void run() { - Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + final Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if(null!=_desktophints) { desktophintsBucket.add(_desktophints); } @@ -256,9 +423,9 @@ public class JAWTUtil { }); desktophints = ( desktophintsBucket.size() > 0 ) ? desktophintsBucket.get(0) : null ; } - } catch (InterruptedException ex) { + } catch (final InterruptedException ex) { ex.printStackTrace(); - } catch (InvocationTargetException ex) { + } catch (final InvocationTargetException ex) { ex.printStackTrace(); } @@ -266,7 +433,7 @@ public class JAWTUtil { System.err.println("JAWTUtil: Has sun.awt.SunToolkit.awtLock/awtUnlock " + hasSunToolkitAWTLock); System.err.println("JAWTUtil: Has Java2D " + j2dExist); System.err.println("JAWTUtil: Is headless " + headlessMode); - int hints = ( null != desktophints ) ? desktophints.size() : 0 ; + final int hints = ( null != desktophints ) ? desktophints.size() : 0 ; System.err.println("JAWTUtil: AWT Desktop hints " + hints); System.err.println("JAWTUtil: OffscreenLayer Supported: "+isOffscreenLayerSupported()+" - Required "+isOffscreenLayerRequired()); } @@ -278,11 +445,11 @@ public class JAWTUtil { public static void initSingleton() { // just exist to ensure static init has been run } - + /** * Called by {@link NativeWindowFactory#shutdown()} */ - public static void shutdown() { + public static void shutdown() { } public static boolean hasJava2D() { @@ -294,7 +461,7 @@ public class JAWTUtil { if(j2dExist) { try { b = ((Boolean)isQueueFlusherThread.invoke(null, (Object[])null)).booleanValue(); - } catch (Exception e) {} + } catch (final Exception e) {} } return b; } @@ -304,58 +471,123 @@ public class JAWTUtil { } /** - * Locks the AWT's global ReentrantLock.<br> - * + * Locks the AWT's global ReentrantLock. + * <p> * JAWT's native Lock() function calls SunToolkit.awtLock(), - * which just uses AWT's global ReentrantLock.<br> + * which just uses AWT's global ReentrantLock. + * </p> + * <p> + * AWT locking is wrapped through a recursive lock object. + * </p> */ - private static void awtLock() { - if(hasSunToolkitAWTLock) { - try { - sunToolkitAWTLockMethod.invoke(null, (Object[])null); - } catch (Exception e) { - throw new NativeWindowException("SunToolkit.awtLock failed", e); + public static void lockToolkit() throws NativeWindowException { + jawtLock.lock(); + if( 1 == jawtLock.getHoldCount() ) { + if(!headlessMode && !isJava2DQueueFlusherThread()) { + if(hasSunToolkitAWTLock) { + try { + sunToolkitAWTLockMethod.invoke(null, (Object[])null); + } catch (final Exception e) { + throw new NativeWindowException("SunToolkit.awtLock failed", e); + } + } else { + jawtLockObject.Lock(); + } } - } else { - jawtLockObject.Lock(); } + if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock(): "+jawtLock); } } /** - * Unlocks the AWT's global ReentrantLock.<br> - * + * Unlocks the AWT's global ReentrantLock. + * <p> * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), - * which just uses AWT's global ReentrantLock.<br> + * which just uses AWT's global ReentrantLock. + * </p> + * <p> + * AWT unlocking is wrapped through a recursive lock object. + * </p> */ - private static void awtUnlock() { - if(hasSunToolkitAWTLock) { - try { - sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); - } catch (Exception e) { - throw new NativeWindowException("SunToolkit.awtUnlock failed", e); + public static void unlockToolkit() { + jawtLock.validateLocked(); + if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock(): "+jawtLock); } + if( 1 == jawtLock.getHoldCount() ) { + if(!headlessMode && !isJava2DQueueFlusherThread()) { + if(hasSunToolkitAWTLock) { + try { + sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); + } catch (final Exception e) { + throw new NativeWindowException("SunToolkit.awtUnlock failed", e); + } + } else { + jawtLockObject.Unlock(); + } } - } else { - jawtLockObject.Unlock(); } + jawtLock.unlock(); } - public static void lockToolkit() throws NativeWindowException { - if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock()"); } - if(!headlessMode && !isJava2DQueueFlusherThread()) { - awtLock(); - } - } - - public static void unlockToolkit() { - if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock()"); } - if(!headlessMode && !isJava2DQueueFlusherThread()) { - awtUnlock(); - } + public static final void validateLocked() throws RuntimeException { + jawtLock.validateLocked(); } public static ToolkitLock getJAWTToolkitLock() { return jawtToolkitLock; } - + + /** + * Returns the pixel scale factor of the given {@link GraphicsDevice}, if supported. + * <p> + * If the component does not support pixel scaling the default + * <code>one</code> is returned. + * </p> + * <p> + * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays + * </p> + * @param device the {@link GraphicsDevice} instance used to query the pixel scale + * @return the pixel scale factor + */ + public static final int getPixelScale(final GraphicsDevice device) { + if( !SKIP_AWT_HIDPI ) { + if( null != getScaleFactorMethod ) { + try { + final Object res = getScaleFactorMethod.invoke(device); + if (res instanceof Integer) { + return ((Integer)res).intValue(); + } + } catch (final Throwable t) {} + } + } + return 1; + } + + /** + * Returns the pixel scale factor of the given {@link GraphicsConfiguration}'s {@link GraphicsDevice}, if supported. + * <p> + * If the {@link GraphicsDevice} is <code>null</code>, <code>zero</code> is returned. + * </p> + * <p> + * If the component does not support pixel scaling the default + * <code>one</code> is returned. + * </p> + * <p> + * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays + * </p> + * @param gc the {@link GraphicsConfiguration} instance used to query the pixel scale + * @return the pixel scale factor + */ + public static final int getPixelScale(final GraphicsConfiguration gc) { + final GraphicsDevice device = null != gc ? gc.getDevice() : null; + final int ps; + if( null == device ) { + ps = 0; + } else { + ps = JAWTUtil.getPixelScale(device); + } + if( DEBUG ) { + System.err.println("JAWTUtil.updatePixelScale: Fetched "+ps); + } + return ps; + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java index 40d7b8032..4f12d1925 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWT_PlatformInfo.java @@ -1,21 +1,21 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -28,11 +28,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index 5fd242247..fae8db52a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,30 +29,35 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ package jogamp.nativewindow.jawt.macosx; +import java.awt.Component; import java.nio.Buffer; import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.util.Point; +import com.jogamp.common.util.PropertyAccess; import com.jogamp.nativewindow.awt.JAWTWindow; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.awt.AWTMisc; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; import jogamp.nativewindow.jawt.JAWTUtil; @@ -62,72 +67,191 @@ import jogamp.nativewindow.jawt.macosx.JAWT_MacOSXDrawingSurfaceInfo; import jogamp.nativewindow.macosx.OSXUtil; public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { - public MacOSXJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + /** May lead to deadlock, due to AWT pos comparison .. don't enable for Applets! */ + private static final boolean DEBUG_CALAYER_POS_CRITICAL; + + static { + Debug.initSingleton(); + DEBUG_CALAYER_POS_CRITICAL = PropertyAccess.isPropertyDefined("nativewindow.debug.JAWT.OSXCALayerPos", true /* jnlpAlias */); + } + + public MacOSXJAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { super(comp, config); if(DEBUG) { dumpInfo(); } } + @Override protected void invalidateNative() { - offscreenSurfaceHandle=0; - offscreenSurfaceHandleSet=false; - if(isOffscreenLayerSurfaceEnabled()) { - if(0 != rootSurfaceLayerHandle) { - OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); - rootSurfaceLayerHandle = 0; - } + if(DEBUG) { + System.err.println("MacOSXJAWTWindow.invalidateNative(): osh-enabled "+isOffscreenLayerSurfaceEnabled()+ + ", osd-set "+offscreenSurfaceDrawableSet+ + ", osd "+toHexString(offscreenSurfaceDrawable)+ + ", osl "+toHexString(getAttachedSurfaceLayer())+ + ", rsl "+toHexString(rootSurfaceLayer)+ + ", wh "+toHexString(windowHandle)+" - "+Thread.currentThread().getName()); + } + offscreenSurfaceDrawable=0; + offscreenSurfaceDrawableSet=false; + if( isOffscreenLayerSurfaceEnabled() ) { if(0 != windowHandle) { OSXUtil.DestroyNSWindow(windowHandle); } + OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { + @Override + public void run() { + if( 0 != rootSurfaceLayer ) { + if( 0 != jawtSurfaceLayersHandle) { + UnsetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer); + } + OSXUtil.DestroyCALayer(rootSurfaceLayer); + rootSurfaceLayer = 0; + } + jawtSurfaceLayersHandle = 0; + } + }); } windowHandle=0; } + @Override + public void setSurfaceScale(final int[] pixelScale) { + super.setSurfaceScale(pixelScale); + if( 0 != getWindowHandle() ) { // locked at least once ! + final int hadPixelScaleX = getPixelScaleX(); + updatePixelScale(); + + if( hadPixelScaleX != getPixelScaleX() && 0 != getAttachedSurfaceLayer() ) { + OSXUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + final long osl = getAttachedSurfaceLayer(); + if( 0 != osl ) { + OSXUtil.SetCALayerPixelScale(rootSurfaceLayer, osl, getPixelScaleX()); + } + } + }); + } + } + } + + @Override protected void attachSurfaceLayerImpl(final long layerHandle) { - OSXUtil.AddCASublayer(rootSurfaceLayerHandle, layerHandle); + OSXUtil.RunOnMainThread(false, false /* kickNSApp */, new Runnable() { + @Override + public void run() { + // AWT position is top-left w/ insets, where CALayer position is bottom/left from root CALayer w/o insets. + // Determine p0: components location on screen w/o insets. + // CALayer position will be determined in native code. + // See detailed description in {@link JAWTUtil#JAWT_OSX_CALAYER_QUIRK_LAYOUT} + final Point p0 = new Point(); + final Component outterComp = getLocationOnScreenNonBlocking(p0, component); + final java.awt.Insets outterInsets = AWTMisc.getInsets(outterComp, true); + final Point p1 = (Point)p0.cloneMutable(); + p1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + p1.translate(-outterInsets.left, -outterInsets.top); + } + + if( DEBUG_CALAYER_POS_CRITICAL ) { + final java.awt.Point pA0 = component.getLocationOnScreen(); + final Point pA1 = new Point(pA0.x, pA0.y); + pA1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + pA1.translate(-outterInsets.left, -outterInsets.top); + } + System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], pA "+pA0+" -> "+pA1+ + ", p0 "+p0+" -> "+p1+", bounds "+bounds); + } else if( DEBUG ) { + System.err.println("JAWTWindow.attachSurfaceLayerImpl: "+toHexString(layerHandle) + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds); + } + // HiDPI: uniform pixel scale + OSXUtil.AddCASublayer(rootSurfaceLayer, layerHandle, p1.getX(), p1.getY(), getWidth(), getHeight(), getPixelScaleX(), JAWTUtil.getOSXCALayerQuirks()); + } } ); + } + + @Override + protected void layoutSurfaceLayerImpl(final long layerHandle, final boolean visible) { + final int caLayerQuirks = JAWTUtil.getOSXCALayerQuirks(); + // AWT position is top-left w/ insets, where CALayer position is bottom/left from root CALayer w/o insets. + // Determine p0: components location on screen w/o insets. + // CALayer position will be determined in native code. + // See detailed description in {@link JAWTUtil#JAWT_OSX_CALAYER_QUIRK_LAYOUT} + final Point p0 = new Point(); + final Component outterComp = getLocationOnScreenNonBlocking(p0, component); + final java.awt.Insets outterInsets = AWTMisc.getInsets(outterComp, true); + final Point p1 = (Point)p0.cloneMutable(); + p1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + p1.translate(-outterInsets.left, -outterInsets.top); + } + + if( DEBUG_CALAYER_POS_CRITICAL ) { + final java.awt.Point pA0 = component.getLocationOnScreen(); + final Point pA1 = new Point(pA0.x, pA0.y); + pA1.translate(-outterComp.getX(), -outterComp.getY()); + if( null != outterInsets ) { + pA1.translate(-outterInsets.left, -outterInsets.top); + } + System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", quirks "+caLayerQuirks+", visible "+visible+ + ", [ins "+outterInsets+"], pA "+pA0+" -> "+pA1+ + ", p0 "+p0+" -> "+p1+", bounds "+bounds); + } else if( DEBUG ) { + System.err.println("JAWTWindow.layoutSurfaceLayerImpl: "+toHexString(layerHandle) + ", quirks "+caLayerQuirks+", visible "+visible+ + ", [ins "+outterInsets+"], p0 "+p0+" -> "+p1+", bounds "+bounds); + } + OSXUtil.FixCALayerLayout(rootSurfaceLayer, layerHandle, visible, p1.getX(), p1.getY(), getWidth(), getHeight(), caLayerQuirks); } - - protected void detachSurfaceLayerImpl(final long layerHandle) { - OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle); + + @Override + protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) { + OSXUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { + @Override + public void run() { + detachNotify.run(); + OSXUtil.RemoveCASublayer(rootSurfaceLayer, layerHandle); + } }); } - + @Override public final long getWindowHandle() { return windowHandle; } - + @Override public final long getSurfaceHandle() { - return offscreenSurfaceHandleSet ? offscreenSurfaceHandle : drawable /* super.getSurfaceHandle() */ ; + return offscreenSurfaceDrawableSet ? offscreenSurfaceDrawable : drawable /* super.getSurfaceHandle() */ ; } - - public void setSurfaceHandle(long surfaceHandle) { + + @Override + public void setSurfaceHandle(final long surfaceHandle) { if( !isOffscreenLayerSurfaceEnabled() ) { throw new java.lang.UnsupportedOperationException("Not using CALAYER"); } if(DEBUG) { - System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): "+toHexString(surfaceHandle)); } - this.offscreenSurfaceHandle = surfaceHandle; - this.offscreenSurfaceHandleSet = true; + this.offscreenSurfaceDrawable = surfaceHandle; + this.offscreenSurfaceDrawableSet = true; } + @Override protected JAWT fetchJAWTImpl() throws NativeWindowException { // use offscreen if supported and [ applet or requested ] return JAWTUtil.getJAWT(getShallUseOffscreenLayer() || isApplet()); } + + @Override protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SURFACE_NOT_READY; - if(null == ds) { - ds = getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } + int ret = NativeSurface.LOCK_SURFACE_NOT_READY; + ds = getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + unlockSurfaceImpl(); + return NativeSurface.LOCK_SURFACE_NOT_READY; } - int res = ds.Lock(); + final int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; if (!dsLocked) { unlockSurfaceImpl(); @@ -139,25 +263,24 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { // conditions can cause this code to be triggered -- should test // more) if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { - ret = NativeWindow.LOCK_SURFACE_CHANGED; + ret = NativeSurface.LOCK_SURFACE_CHANGED; } - if(null == dsi) { - if (firstLock) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - dsi = ds.GetDrawingSurfaceInfo(); - return null; - } - }); - } else { - dsi = ds.GetDrawingSurfaceInfo(); - } - if (dsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } + if (firstLock) { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + dsi = ds.GetDrawingSurfaceInfo(); + return null; + } + }); + } else { + dsi = ds.GetDrawingSurfaceInfo(); } - updateBounds(dsi.getBounds()); + if (dsi == null) { + unlockSurfaceImpl(); + return NativeSurface.LOCK_SURFACE_NOT_READY; + } + updateLockedData(dsi.getBounds()); if (DEBUG && firstLock ) { dumpInfo(); } @@ -166,24 +289,24 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (macosxdsi == null) { unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + return NativeSurface.LOCK_SURFACE_NOT_READY; } drawable = macosxdsi.getCocoaViewRef(); - + if (drawable == 0) { unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + return NativeSurface.LOCK_SURFACE_NOT_READY; } else { windowHandle = OSXUtil.GetNSWindow(drawable); - ret = NativeWindow.LOCK_SUCCESS; + ret = NativeSurface.LOCK_SUCCESS; } } else { /** * Only create a fake invisible NSWindow for the drawable handle * to please frameworks requiring such (eg. NEWT). - * - * The actual surface/ca-layer shall be created/attached - * by the upper framework (JOGL) since they require more information. + * + * The actual surface/ca-layer shall be created/attached + * by the upper framework (JOGL) since they require more information. */ String errMsg = null; if(0 == drawable) { @@ -193,31 +316,44 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } else { drawable = OSXUtil.GetNSView(windowHandle); if(0 == drawable) { - errMsg = "Null NSView of NSWindow 0x"+Long.toHexString(windowHandle); + errMsg = "Null NSView of NSWindow "+toHexString(windowHandle); } } if(null == errMsg) { - // fix caps reflecting offscreen! (no GL available here ..) - Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + // Fix caps reflecting offscreen! (no GL available here ..) + final Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); caps.setOnscreen(false); setChosenCapabilities(caps); } } if(null == errMsg) { - if(0 == rootSurfaceLayerHandle) { - rootSurfaceLayerHandle = OSXUtil.CreateCALayer(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); - if(0 == rootSurfaceLayerHandle) { - errMsg = "Could not create root CALayer"; - } else if(!SetJAWTRootSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) { - errMsg = "Could not set JAWT rootSurfaceLayerHandle 0x"+Long.toHexString(rootSurfaceLayerHandle); - } - } + jawtSurfaceLayersHandle = GetJAWTSurfaceLayersHandle0(dsi.getBuffer()); + OSXUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + String errMsg = null; + if(0 == rootSurfaceLayer && 0 != jawtSurfaceLayersHandle) { + rootSurfaceLayer = OSXUtil.CreateCALayer(bounds.getWidth(), bounds.getHeight(), getPixelScaleX()); // HiDPI: uniform pixel scale + if(0 == rootSurfaceLayer) { + errMsg = "Could not create root CALayer"; + } else { + try { + SetJAWTRootSurfaceLayer0(jawtSurfaceLayersHandle, rootSurfaceLayer); + } catch(final Exception e) { + errMsg = "Could not set JAWT rootSurfaceLayerHandle "+toHexString(rootSurfaceLayer)+", cause: "+e.getMessage(); + } + } + if(null != errMsg) { + if(0 != rootSurfaceLayer) { + OSXUtil.DestroyCALayer(rootSurfaceLayer); + rootSurfaceLayer = 0; + } + throw new NativeWindowException(errMsg+": "+MacOSXJAWTWindow.this); + } + } + } } ); } if(null != errMsg) { - if(0 != rootSurfaceLayerHandle) { - OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); - rootSurfaceLayerHandle = 0; - } if(0 != windowHandle) { OSXUtil.DestroyNSWindow(windowHandle); windowHandle = 0; @@ -226,12 +362,13 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { unlockSurfaceImpl(); throw new NativeWindowException(errMsg+": "+this); } - ret = NativeWindow.LOCK_SUCCESS; + ret = NativeSurface.LOCK_SUCCESS; } - + return ret; } - + + @Override protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -250,7 +387,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { System.err.println("MaxOSXJAWTWindow: 0x"+Integer.toHexString(this.hashCode())+" - thread: "+Thread.currentThread().getName()); dumpJAWTInfo(); } - + /** * {@inheritDoc} * <p> @@ -260,32 +397,48 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { * .. * ds = getJAWT().GetDrawingSurface(component); * due to a SIGSEGV. - * + * * Hence we have some threading / sync issues with the native JAWT implementation. - * </p> + * </p> */ @Override - public Point getLocationOnScreen(Point storage) { - return getLocationOnScreenNonBlocking(storage, component); - } + public Point getLocationOnScreen(Point storage) { + if( null == storage ) { + storage = new Point(); + } + getLocationOnScreenNonBlocking(storage, component); + return storage; + } + @Override protected Point getLocationOnScreenNativeImpl(final int x0, final int y0) { return null; } - private static native boolean SetJAWTRootSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); - // private static native boolean UnsetJAWTRootSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); - + + private static native long GetJAWTSurfaceLayersHandle0(Buffer jawtDrawingSurfaceInfoBuffer); + + /** + * Set the given root CALayer in the JAWT surface + */ + private static native void SetJAWTRootSurfaceLayer0(long jawtSurfaceLayersHandle, long caLayer); + + /** + * Unset the given root CALayer in the JAWT surface, passing the NIO DrawingSurfaceInfo buffer + */ + private static native void UnsetJAWTRootSurfaceLayer0(long jawtSurfaceLayersHandle, long caLayer); + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; - + private long jawtSurfaceLayersHandle; + private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; - - private long rootSurfaceLayerHandle = 0; // attached to the JAWT_SurfaceLayer - + + private volatile long rootSurfaceLayer = 0; // attached to the JAWT_SurfaceLayer + private long windowHandle = 0; - private long offscreenSurfaceHandle = 0; - private boolean offscreenSurfaceHandleSet = false; - + private long offscreenSurfaceDrawable = 0; + private boolean offscreenSurfaceDrawableSet = false; + // Workaround for instance of 4796548 private boolean firstLock = true; diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java index 74dabb67f..5d191f7e5 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -65,6 +65,7 @@ public class Win32SunJDKReflection { static { AccessController.doPrivileged(new PrivilegedAction() { + @Override public Object run() { try { win32GraphicsDeviceClass = Class.forName("sun.awt.Win32GraphicsDevice"); @@ -74,7 +75,7 @@ public class Win32SunJDKReflection { win32GraphicsConfigGetVisualMethod = win32GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); win32GraphicsConfigGetVisualMethod.setAccessible(true); initted = true; - } catch (Exception e) { + } catch (final Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } return null; @@ -82,37 +83,37 @@ public class Win32SunJDKReflection { }); } - public static GraphicsConfiguration graphicsConfigurationGet(GraphicsDevice device, int pfdID) { + public static GraphicsConfiguration graphicsConfigurationGet(final GraphicsDevice device, final int pfdID) { if (!initted) { return null; } try { - return (GraphicsConfiguration) win32GraphicsConfigGetConfigMethod.invoke(null, new Object[] { device, new Integer(pfdID) }); - } catch (Exception e) { + return (GraphicsConfiguration) win32GraphicsConfigGetConfigMethod.invoke(null, new Object[] { device, Integer.valueOf(pfdID) }); + } catch (final Exception e) { return null; } } - public static int graphicsConfigurationGetPixelFormatID(AbstractGraphicsConfiguration config) { + public static int graphicsConfigurationGetPixelFormatID(final AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; - } catch (Exception e) { + } catch (final Exception e) { return 0; } } - public static int graphicsConfigurationGetPixelFormatID(GraphicsConfiguration config) { + public static int graphicsConfigurationGetPixelFormatID(final GraphicsConfiguration config) { if (!initted) { return 0; } try { return ((Integer) win32GraphicsConfigGetVisualMethod.invoke(config, (Object[])null)).intValue(); - } catch (Exception e) { + } catch (final Exception e) { return 0; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 5d1d43792..7ad914e0a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -41,6 +41,7 @@ package jogamp.nativewindow.jawt.windows; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; @@ -56,34 +57,30 @@ import jogamp.nativewindow.windows.GDIUtil; public class WindowsJAWTWindow extends JAWTWindow { - public WindowsJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + public WindowsJAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { super(comp, config); } + @Override protected void invalidateNative() { windowHandle = 0; } - protected void attachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected void detachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - + @Override protected JAWT fetchJAWTImpl() throws NativeWindowException { return JAWTUtil.getJAWT(false); // no offscreen } - + + @Override protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; + int ret = NativeSurface.LOCK_SUCCESS; ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - int res = ds.Lock(); + final int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; if (!dsLocked) { unlockSurfaceImpl(); @@ -102,7 +99,7 @@ public class WindowsJAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - updateBounds(dsi.getBounds()); + updateLockedData(dsi.getBounds()); win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (win32dsi == null) { unlockSurfaceImpl(); @@ -117,6 +114,7 @@ public class WindowsJAWTWindow extends JAWTWindow { return ret; } + @Override protected void unlockSurfaceImpl() throws NativeWindowException { drawable = 0; // invalid HDC if(null!=ds) { @@ -138,7 +136,8 @@ public class WindowsJAWTWindow extends JAWTWindow { return windowHandle; } - protected Point getLocationOnScreenNativeImpl(int x, int y) { + @Override + protected Point getLocationOnScreenNativeImpl(final int x, final int y) { return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 736718de8..9abaed731 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,7 +29,7 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. @@ -38,6 +38,7 @@ package jogamp.nativewindow.jawt.x11; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; @@ -53,32 +54,28 @@ import jogamp.nativewindow.x11.X11Lib; public class X11JAWTWindow extends JAWTWindow { - public X11JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + public X11JAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) { super(comp, config); } + @Override protected void invalidateNative() { } - protected void attachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - protected void detachSurfaceLayerImpl(final long layerHandle) { - throw new UnsupportedOperationException("offscreen layer not supported"); - } - + @Override protected JAWT fetchJAWTImpl() throws NativeWindowException { return JAWTUtil.getJAWT(false); // no offscreen } - + + @Override protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; + int ret = NativeSurface.LOCK_SUCCESS; ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - int res = ds.Lock(); + final int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; if (!dsLocked) { unlockSurfaceImpl(); @@ -97,7 +94,7 @@ public class X11JAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - updateBounds(dsi.getBounds()); + updateLockedData(dsi.getBounds()); x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (x11dsi == null) { unlockSurfaceImpl(); @@ -111,6 +108,7 @@ public class X11JAWTWindow extends JAWTWindow { return ret; } + @Override protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -126,14 +124,16 @@ public class X11JAWTWindow extends JAWTWindow { x11dsi = null; } - protected Point getLocationOnScreenNativeImpl(int x, int y) { - return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + @Override + protected Point getLocationOnScreenNativeImpl(final int x, final int y) { + // surface is locked and hence the device + return X11Lib.GetRelativeLocation(getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } - + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; private JAWT_X11DrawingSurfaceInfo x11dsi; - + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java index 27e0a5e50..fea1be11a 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -29,11 +29,11 @@ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * + * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. - * + * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ @@ -65,6 +65,7 @@ public class X11SunJDKReflection { static { AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override public Object run() { try { x11GraphicsDeviceClass = Class.forName("sun.awt.X11GraphicsDevice"); @@ -75,7 +76,7 @@ public class X11SunJDKReflection { x11GraphicsConfigGetVisualMethod = x11GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); x11GraphicsConfigGetVisualMethod.setAccessible(true); initialized = true; - } catch (Exception e) { + } catch (final Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } return null; @@ -83,37 +84,37 @@ public class X11SunJDKReflection { }); } - public static long graphicsDeviceGetDisplay(GraphicsDevice device) { + public static long graphicsDeviceGetDisplay(final GraphicsDevice device) { if (!initialized) { return 0; } try { return ((Long) x11GraphicsDeviceGetDisplayMethod.invoke(device, (Object[])null)).longValue(); - } catch (Exception e) { + } catch (final Exception e) { return 0; } } - public static int graphicsConfigurationGetVisualID(AbstractGraphicsConfiguration config) { + public static int graphicsConfigurationGetVisualID(final AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; - } catch (Exception e) { + } catch (final Exception e) { return 0; } } - public static int graphicsConfigurationGetVisualID(GraphicsConfiguration config) { + public static int graphicsConfigurationGetVisualID(final GraphicsConfiguration config) { if (!initialized) { return 0; } try { return ((Integer) x11GraphicsConfigGetVisualMethod.invoke(config, (Object[])null)).intValue(); - } catch (Exception e) { + } catch (final Exception e) { return 0; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java index de3206c0c..6b54c32ea 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java @@ -9,39 +9,39 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; public class OSXDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { long nsWindow; - + /** - * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, - * not the actual dummy surface width. + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. * The latter is platform specific and small - * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, * not the actual dummy surface height, * The latter is platform specific and small */ - public OSXDummyUpstreamSurfaceHook(int width, int height) { + public OSXDummyUpstreamSurfaceHook(final int width, final int height) { super(width, height); nsWindow = 0; } - + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { if(0 == nsWindow && 0 == s.getSurfaceHandle()) { nsWindow = OSXUtil.CreateNSWindow(0, 0, 64, 64); if(0 == nsWindow) { throw new NativeWindowException("Error NS window 0"); } - long nsView = OSXUtil.GetNSView(nsWindow); + final long nsView = OSXUtil.GetNSView(nsWindow); if(0 == nsView) { throw new NativeWindowException("Error NS view 0"); } s.setSurfaceHandle(nsView); - s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); } - + @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { if( 0 == nsWindow || 0 == s.getSurfaceHandle() ) { throw new InternalError("Owns upstream surface, but no OSX view/window: "+s+", nsWindow 0x"+Long.toHexString(nsWindow)); diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index b7a83e133..cf163bd82 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -32,15 +32,24 @@ import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; +import com.jogamp.common.util.Function; +import com.jogamp.common.util.FunctionTask; +import com.jogamp.common.util.RunnableTask; + import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; -public class OSXUtil { - private static boolean isInit = false; +public class OSXUtil implements ToolkitProperties { + private static boolean isInit = false; private static final boolean DEBUG = Debug.debug("OSXUtil"); - + + /** FIXME HiDPI: OSX unique and maximum value {@value} */ + public static final int MAX_PIXELSCALE = 2; + /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static synchronized void initSingleton() { if(!isInit) { @@ -50,121 +59,318 @@ public class OSXUtil { if(!NWJNILibLoader.loadNativeWindow("macosx")) { throw new NativeWindowException("NativeWindow MacOSX native library load error."); } - + if( !initIDs0() ) { throw new NativeWindowException("MacOSX: Could not initialized native stub"); - } + } isInit = true; } } /** * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties */ - public static void shutdown() { - } - - public static boolean requiresToolkitLock() { - return false; - } - - public static boolean isNSView(long object) { - return isNSView0(object); + public static void shutdown() { } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static boolean requiresToolkitLock() { return false; } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { return false; } + + public static boolean isNSView(final long object) { + return 0 != object ? isNSView0(object) : false; } - - public static boolean isNSWindow(long object) { - return isNSWindow0(object); + + public static boolean isNSWindow(final long object) { + return 0 != object ? isNSWindow0(object) : false; } - + /** - * In case the <code>windowOrView</code> is top-level, - * you shall set <code>topLevel</code> to true where - * insets gets into account to compute the client position as follows: - * <pre> - if(topLevel) { - // top-level position -> client window position - final Insets insets = GetInsets(windowOrView); - los.setX(los.getX() + insets.getLeftWidth()); - los.setY(los.getY() + insets.getTopHeight()); - } - * </pre> * @param windowOrView - * @param topLevel * @param src_x * @param src_y - * @return the client position + * @return top-left client-area position in window units */ - public static Point GetLocationOnScreen(long windowOrView, boolean topLevel, int src_x, int src_y) { - final Point los = (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); - if(topLevel) { - // top-level position -> client window position - final Insets insets = GetInsets(windowOrView); - los.setX(los.getX() + insets.getLeftWidth()); - los.setY(los.getY() + insets.getTopHeight()); - } - return los; + public static Point GetLocationOnScreen(final long windowOrView, final int src_x, final int src_y) { + return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); } - - public static Insets GetInsets(long windowOrView) { + + public static Insets GetInsets(final long windowOrView) { return (Insets) GetInsets0(windowOrView); } - - public static long CreateNSWindow(int x, int y, int width, int height) { + + public static double GetPixelScale(final int screenIndex) { + return GetPixelScale0(screenIndex); + } + + public static double GetPixelScale(final long windowOrView) { + return GetPixelScale1(windowOrView); + } + + public static long CreateNSWindow(final int x, final int y, final int width, final int height) { return CreateNSWindow0(x, y, width, height); } - public static void DestroyNSWindow(long nsWindow) { + public static void DestroyNSWindow(final long nsWindow) { DestroyNSWindow0(nsWindow); } - public static long GetNSView(long nsWindow) { + public static long GetNSView(final long nsWindow) { return GetNSView0(nsWindow); } - public static long GetNSWindow(long nsView) { + public static long GetNSWindow(final long nsView) { return GetNSWindow0(nsView); } - - public static long CreateCALayer(int x, int y, int width, int height) { - return CreateCALayer0(x, y, width, height); + + /** + * Create a CALayer suitable to act as a root CALayer. + * @param width width of the CALayer in window units (points) + * @param height height of the CALayer in window units (points) + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + * @return the new CALayer object + * @see #DestroyCALayer(long) + * @see #AddCASublayer(long, long) + */ + public static long CreateCALayer(final int width, final int height, final float contentsScale) { + final long l = CreateCALayer0(width, height, contentsScale); + if(DEBUG) { + System.err.println("OSXUtil.CreateCALayer: 0x"+Long.toHexString(l)+" - "+Thread.currentThread().getName()); + } + return l; } - public static void AddCASublayer(long rootCALayer, long subCALayer) { + + /** + * Attach a sub CALayer to the root CALayer + * <p> + * Method will trigger a <code>display</code> + * call to the CALayer hierarchy to enforce resource creation if required, e.g. an NSOpenGLContext. + * </p> + * <p> + * Hence it is important that related resources are not locked <i>if</i> + * they will be used for creation. + * </p> + * @param rootCALayer + * @param subCALayer + * @param x x-coord of the sub-CALayer in window units (points) + * @param y y-coord of the sub-CALayer in window units (points) + * @param width width of the sub-CALayer in window units (points) + * @param height height of the sub-CALayer in window units (points) + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + * @param caLayerQuirks + * @see #CreateCALayer(int, int, float) + * @see #RemoveCASublayer(long, long, boolean) + */ + public static void AddCASublayer(final long rootCALayer, final long subCALayer, + final int x, final int y, final int width, final int height, + final float contentsScale, final int caLayerQuirks) { if(0==rootCALayer || 0==subCALayer) { throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); } - AddCASublayer0(rootCALayer, subCALayer); + if(DEBUG) { + System.err.println("OSXUtil.AttachCALayer: caLayerQuirks "+caLayerQuirks+", 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName()); + } + AddCASublayer0(rootCALayer, subCALayer, x, y, width, height, contentsScale, caLayerQuirks); + } + + /** + * Fix root and sub CALayer position to 0/0 and size + * <p> + * If the sub CALayer implements the Objective-C NativeWindow protocol NWDedicatedSize (e.g. JOGL's MyNSOpenGLLayer), + * the dedicated size is passed to the layer, which propagates it appropriately. + * </p> + * <p> + * On OSX/Java7 our root CALayer's frame position and size gets corrupted by its NSView, + * hence we have created the NWDedicatedSize protocol. + * </p> + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param visible TODO + * @param width the expected width in window units (points) + * @param height the expected height in window units (points) + * @param caLayerQuirks TODO + */ + public static void FixCALayerLayout(final long rootCALayer, final long subCALayer, final boolean visible, final int x, final int y, final int width, final int height, final int caLayerQuirks) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + FixCALayerLayout0(rootCALayer, subCALayer, visible, x, y, width, height, caLayerQuirks); + } + + /** + * Set root and sub CALayer pixelScale / contentScale for HiDPI + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static void SetCALayerPixelScale(final long rootCALayer, final long subCALayer, final float contentsScale) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + SetCALayerPixelScale0(rootCALayer, subCALayer, contentsScale); } - public static void RemoveCASublayer(long rootCALayer, long subCALayer) { + + /** + * Detach a sub CALayer from the root CALayer. + */ + public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) { if(0==rootCALayer || 0==subCALayer) { throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); } + if(DEBUG) { + System.err.println("OSXUtil.DetachCALayer: 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName()); + } RemoveCASublayer0(rootCALayer, subCALayer); } - public static void DestroyCALayer(long caLayer) { + + /** + * Destroy a CALayer. + * @see #CreateCALayer(int, int, float) + */ + public static void DestroyCALayer(final long caLayer) { if(0==caLayer) { throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); } - DestroyCALayer0(caLayer); + if(DEBUG) { + System.err.println("OSXUtil.DestroyCALayer: 0x"+Long.toHexString(caLayer)+" - "+Thread.currentThread().getName()); + } + DestroyCALayer0(caLayer); } - - public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) { - if(IsMainThread0()) { + + /** + * Run on OSX UI main thread. + * <p> + * 'waitUntilDone' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread. + * </p> + * + * @param waitUntilDone + * @param kickNSApp if <code>true</code> issues {@link #KickNSApp()} + * @param runnable + */ + public static void RunOnMainThread(final boolean waitUntilDone, final boolean kickNSApp, final Runnable runnable) { + if( IsMainThread0() ) { runnable.run(); // don't leave the JVM } else { - RunOnMainThread0(waitUntilDone, runnable); + // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, + // otherwise we may freeze the OSX main thread. + Throwable throwable = null; + final Object sync = new Object(); + final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); + synchronized(sync) { + RunOnMainThread0(kickNSApp, rt); + if( waitUntilDone ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rt.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + } + } + + /** + * Run later on .. + * @param onMain if true, run on main-thread, otherwise on the current OSX thread. + * @param runnable + * @param delay delay to run the runnable in milliseconds + */ + public static void RunLater(final boolean onMain, final Runnable runnable, final int delay) { + RunLater0(onMain, false /* kickNSApp */, new RunnableTask( runnable, null, true, System.err ), delay); + } + + /** + * Wakes up NSApp thread by sending an empty NSEvent .. + * <p> + * This is deemed important <i>sometimes</i> where resources shall get freed ASAP, e.g. GL context etc. + * </p> + * <p> + * The following scenarios requiring this <i>wake-up</i> are currently known: + * <ul> + * <li>Destruction of an OpenGL context</li> + * <li>Destruction of Windows .. ?</li> + * <li>Stopping the NSApp</li> + * </ul> + * </p> + * FIXME: Complete list of scenarios and reason it. + */ + public static void KickNSApp() { + KickNSApp0(); + } + + private static Runnable _nop = new Runnable() { @Override public void run() {}; }; + + /** Issues a {@link #RunOnMainThread(boolean, boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done and issuing {@link #KickNSApp()}. */ + public static void WaitUntilFinish() { + RunOnMainThread(true, true /* kickNSApp */, _nop); + } + + /** + * Run on OSX UI main thread. + * <p> + * 'waitUntilDone' is implemented on Java site via lock/wait on {@link FunctionTask} to not freeze OSX main thread. + * </p> + * + * @param waitUntilDone + * @param kickNSApp if <code>true</code> issues {@link #KickNSApp()} + * @param func + */ + public static <R,A> R RunOnMainThread(final boolean waitUntilDone, final boolean kickNSApp, final Function<R,A> func, final A... args) { + if( IsMainThread0() ) { + return func.eval(args); // don't leave the JVM + } else { + // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, + // otherwise we may freeze the OSX main thread. + Throwable throwable = null; + final Object sync = new Object(); + final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); + synchronized(sync) { + rt.setArgs(args); + RunOnMainThread0(kickNSApp, rt); + if( waitUntilDone ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rt.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + return rt.getResult(); } } - + public static boolean IsMainThread() { return IsMainThread0(); } - + /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */ - public static int GetScreenRefreshRate(int scrn_idx) { + public static int GetScreenRefreshRate(final int scrn_idx) { return GetScreenRefreshRate0(scrn_idx); } - + /*** private static boolean isAWTEDTMainThreadInit = false; private static boolean isAWTEDTMainThread; - + public synchronized static boolean isAWTEDTMainThread() { if(!isAWTEDTMainThreadInit) { isAWTEDTMainThreadInit = true; @@ -178,24 +384,30 @@ public class OSXUtil { } else { isAWTEDTMainThread = false; } - } + } return isAWTEDTMainThread; } */ - + private static native boolean initIDs0(); private static native boolean isNSView0(long object); private static native boolean isNSWindow0(long object); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); private static native Object GetInsets0(long windowOrView); + private static native double GetPixelScale0(int screenIndex); + private static native double GetPixelScale1(long windowOrView); private static native long CreateNSWindow0(int x, int y, int width, int height); private static native void DestroyNSWindow0(long nsWindow); private static native long GetNSView0(long nsWindow); private static native long GetNSWindow0(long nsView); - private static native long CreateCALayer0(int x, int y, int width, int height); - private static native void AddCASublayer0(long rootCALayer, long subCALayer); + private static native long CreateCALayer0(int width, int height, float contentsScale); + private static native void AddCASublayer0(long rootCALayer, long subCALayer, int x, int y, int width, int height, float contentsScale, int caLayerQuirks); + private static native void FixCALayerLayout0(long rootCALayer, long subCALayer, boolean visible, int x, int y, int width, int height, int caLayerQuirks); + private static native void SetCALayerPixelScale0(long rootCALayer, long subCALayer, float contentsScale); private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); private static native void DestroyCALayer0(long caLayer); - private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable); + private static native void RunOnMainThread0(boolean kickNSApp, Runnable runnable); + private static native void RunLater0(boolean onMain, boolean kickNSApp, Runnable runnable, int delay); + private static native void KickNSApp0(); private static native boolean IsMainThread0(); private static native int GetScreenRefreshRate0(int scrn_idx); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java index aa5f3dac5..a08cf9b51 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java @@ -9,33 +9,33 @@ import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { /** - * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, - * not the actual dummy surface width. + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. * The latter is platform specific and small - * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, * not the actual dummy surface height, * The latter is platform specific and small */ - public GDIDummyUpstreamSurfaceHook(int width, int height) { + public GDIDummyUpstreamSurfaceHook(final int width, final int height) { super(width, height); } - + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { final GDISurface ms = (GDISurface)s; - if(0 == ms.getWindowHandle()) { + if(0 == ms.getWindowHandle()) { final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, 64, 64); if(0 == windowHandle) { throw new NativeWindowException("Error windowHandle 0, werr: "+GDI.GetLastError()); - } + } ms.setWindowHandle(windowHandle); - ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); } - + @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { final GDISurface ms = (GDISurface)s; if( ms.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { if( 0 == ms.getWindowHandle() ) { @@ -46,5 +46,5 @@ public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize ms.setWindowHandle(0); ms.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } - } + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java index 3db2b5fc9..2f335c428 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java @@ -43,10 +43,12 @@ import jogamp.nativewindow.windows.GDI; * allowing the use of HDC via lockSurface()/unlockSurface() protocol. * The latter will get and release the HDC. * The size via getWidth()/getHeight() is invalid. + * + * @see ProxySurface */ public class GDISurface extends ProxySurfaceImpl { - protected long windowHandle; - protected long surfaceHandle; + private long windowHandle; + private long surfaceHandle; /** * @param cfg the {@link AbstractGraphicsConfiguration} to be used @@ -56,37 +58,37 @@ public class GDISurface extends ProxySurfaceImpl { * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. */ - public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, UpstreamSurfaceHook upstream, boolean ownsDevice) { + public GDISurface(final AbstractGraphicsConfiguration cfg, final long windowHandle, final UpstreamSurfaceHook upstream, final boolean ownsDevice) { super(cfg, upstream, ownsDevice); this.windowHandle=windowHandle; this.surfaceHandle=0; } @Override - protected void invalidateImpl() { + protected void invalidateImpl() { if(0 != surfaceHandle) { throw new NativeWindowException("didn't release surface Handle: "+this); } windowHandle = 0; // surfaceHandle = 0; } - + /** * {@inheritDoc} * <p> - * Actually the window handle (HWND), since the surfaceHandle (HDC) is derived + * Actually the window handle (HWND), since the surfaceHandle (HDC) is derived * from it at {@link #lockSurface()}. - * </p> + * </p> */ @Override - public final void setSurfaceHandle(long surfaceHandle) { + public final void setSurfaceHandle(final long surfaceHandle) { this.windowHandle = surfaceHandle; } /** - * Sets the window handle (HWND). + * Sets the window handle (HWND). */ - public final void setWindowHandle(long windowHandle) { + public final void setWindowHandle(final long windowHandle) { this.windowHandle = windowHandle; } @@ -116,7 +118,7 @@ public class GDISurface extends ProxySurfaceImpl { final protected void unlockSurfaceImpl() { if (0 != surfaceHandle) { if(0 == GDI.ReleaseDC(windowHandle, surfaceHandle)) { - throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); + throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); } surfaceHandle=0; } @@ -126,4 +128,15 @@ public class GDISurface extends ProxySurfaceImpl { final public long getSurfaceHandle() { return surfaceHandle; } + + @Override + public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) { + return pixelUnitsAndResult; // no pixelScale factor + } + + @Override + public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) { + return windowUnitsAndResult; // no pixelScale factor + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java index 613c76032..c409b6a39 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -33,21 +33,22 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.Debug; -import jogamp.nativewindow.x11.X11Util; +import jogamp.nativewindow.ToolkitProperties; -public class GDIUtil { +public class GDIUtil implements ToolkitProperties { private static final boolean DEBUG = Debug.debug("GDIUtil"); - + private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ; private static RegisteredClassFactory dummyWindowClassFactory; - private static boolean isInit = false; - + private static volatile boolean isInit = false; + /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static synchronized void initSingleton() { if(!isInit) { - synchronized(X11Util.class) { + synchronized(GDIUtil.class) { if(!isInit) { if(DEBUG) { System.out.println("GDI.initSingleton()"); @@ -58,53 +59,95 @@ public class GDIUtil { if( !initIDs0() ) { throw new NativeWindowException("GDI: Could not initialized native stub"); } - dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0()); + dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0(), + true /* useDummyDispatchThread */, + 0 /* iconSmallHandle */, 0 /* iconBigHandle */); + if(DEBUG) { + System.out.println("GDI.initSingleton() dummyWindowClassFactory "+dummyWindowClassFactory); + } isInit = true; } } } } - + /** * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties */ - public static void shutdown() { + public static void shutdown() { } - + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ public static boolean requiresToolkitLock() { return false; } - + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { return false; } + private static RegisteredClass dummyWindowClass = null; private static Object dummyWindowSync = new Object(); - - public static long CreateDummyWindow(int x, int y, int width, int height) { + + public static long CreateDummyWindow(final int x, final int y, final int width, final int height) { synchronized(dummyWindowSync) { dummyWindowClass = dummyWindowClassFactory.getSharedClass(); - return CreateDummyWindow0(dummyWindowClass.getHandle(), dummyWindowClass.getName(), dummyWindowClass.getName(), x, y, width, height); + if(DEBUG) { + System.out.println("GDI.CreateDummyWindow() dummyWindowClassFactory "+dummyWindowClassFactory); + System.out.println("GDI.CreateDummyWindow() dummyWindowClass "+dummyWindowClass); + } + return CreateDummyWindow0(dummyWindowClass.getHInstance(), dummyWindowClass.getName(), dummyWindowClass.getHDispThreadContext(), dummyWindowClass.getName(), x, y, width, height); } } - - public static boolean DestroyDummyWindow(long hwnd) { + + public static boolean DestroyDummyWindow(final long hwnd) { boolean res; synchronized(dummyWindowSync) { if( null == dummyWindowClass ) { throw new InternalError("GDI Error ("+dummyWindowClassFactory.getSharedRefCount()+"): SharedClass is null"); } - res = GDI.DestroyWindow(hwnd); + res = DestroyWindow0(dummyWindowClass.getHDispThreadContext(), hwnd); dummyWindowClassFactory.releaseSharedClass(); } return res; } - - public static Point GetRelativeLocation(long src_win, long dest_win, int src_x, int src_y) { + + public static Point GetRelativeLocation(final long src_win, final long dest_win, final int src_x, final int src_y) { return (Point) GetRelativeLocation0(src_win, dest_win, src_x, src_y); } - - public static native boolean CreateWindowClass(long hInstance, String clazzName, long wndProc); - public static native boolean DestroyWindowClass(long hInstance, String className); - + + public static boolean IsUndecorated(final long win) { + return IsUndecorated0(win); + } + + public static boolean IsChild(final long win) { + return IsChild0(win); + } + + public static void SetProcessThreadsAffinityMask(final long affinityMask, final boolean verbose) { + SetProcessThreadsAffinityMask0(affinityMask, verbose); + } + + private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + + /** Creates WNDCLASSEX instance */ + static native boolean CreateWindowClass0(long hInstance, String clazzName, long wndProc, long iconSmallHandle, long iconBigHandle); + /** Destroys WNDCLASSEX instance */ + static native boolean DestroyWindowClass0(long hInstance, String className, long dispThreadCtx); + static native long CreateDummyDispatchThread0(); + private static native boolean initIDs0(); - private static native long getDummyWndProc0(); + private static native long getDummyWndProc0(); private static native Object GetRelativeLocation0(long src_win, long dest_win, int src_x, int src_y); - - static native long CreateDummyWindow0(long hInstance, String className, String windowName, int x, int y, int width, int height); + private static native boolean IsChild0(long win); + private static native boolean IsUndecorated0(long win); + + private static native void SetProcessThreadsAffinityMask0(long affinityMask, boolean verbose); + + private static native long CreateDummyWindow0(long hInstance, String className, long dispThreadCtx, String windowName, int x, int y, int width, int height); + private static native boolean DestroyWindow0(long dispThreadCtx, long win); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java index afb3daf7c..3c7b1adfb 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClass.java @@ -29,17 +29,25 @@ package jogamp.nativewindow.windows; public class RegisteredClass { - long hInstance; - String className; + private final long hInstance; + private final String className; + private final long hDDTCtx; - RegisteredClass(long hInst, String name) { - hInstance = hInst; - className = name; + RegisteredClass(final long hInst, final String name, final long hDispatchThreadCtx) { + this.hInstance = hInst; + this.className = name; + this.hDDTCtx = hDispatchThreadCtx; } - public final long getHandle() { return hInstance; } + /** Application handle, same as {@link RegisteredClassFactory#getHInstance()}. */ + public final long getHInstance() { return hInstance; } + + /** Unique Window Class Name */ public final String getName() { return className; } + /** Unique associated dispatch thread context for this Window Class, or 0 for none. */ + public final long getHDispThreadContext() { return hDDTCtx; } + @Override - public final String toString() { return "RegisteredClass[handle 0x"+Long.toHexString(hInstance)+", "+className+"]"; } + public final String toString() { return "RegisteredClass[handle 0x"+Long.toHexString(hInstance)+", "+className+", dtx 0x"+Long.toHexString(hDDTCtx)+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java index 00bedfc8e..e3ea49314 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java @@ -29,46 +29,76 @@ package jogamp.nativewindow.windows; import jogamp.nativewindow.Debug; + import java.util.ArrayList; + import javax.media.nativewindow.NativeWindowException; public class RegisteredClassFactory { - static final boolean DEBUG = Debug.debug("RegisteredClass"); - private static ArrayList<RegisteredClassFactory> registeredFactories = new ArrayList<RegisteredClassFactory>(); - - private String classBaseName; - private long wndProc; + private static final boolean DEBUG = Debug.debug("RegisteredClass"); + private static final ArrayList<RegisteredClassFactory> registeredFactories; + private static final long hInstance; + + static { + hInstance = GDI.GetApplicationHandle(); + if( 0 == hInstance ) { + throw new NativeWindowException("Error: Null ModuleHandle for Application"); + } + registeredFactories = new ArrayList<RegisteredClassFactory>(); + } + + private final String classBaseName; + private final long wndProc; + private final boolean useDummyDispatchThread; + private final long iconSmallHandle, iconBigHandle; private RegisteredClass sharedClass = null; private int classIter = 0; private int sharedRefCount = 0; private final Object sync = new Object(); + private String toHexString(final long l) { return "0x"+Long.toHexString(l); } + + @Override + public final String toString() { return "RegisteredClassFactory[moduleHandle "+toHexString(hInstance)+", "+classBaseName+ + ", wndProc "+toHexString(wndProc)+", useDDT "+useDummyDispatchThread+", shared[refCount "+sharedRefCount+", class "+sharedClass+"]]"; } + /** - * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. + * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. */ public static void shutdownSharedClasses() { synchronized(registeredFactories) { + if( DEBUG ) { + System.err.println("RegisteredClassFactory.shutdownSharedClasses: "+registeredFactories.size()); + } for(int j=0; j<registeredFactories.size(); j++) { final RegisteredClassFactory rcf = registeredFactories.get(j); synchronized(rcf.sync) { if(null != rcf.sharedClass) { - GDIUtil.DestroyWindowClass(rcf.sharedClass.getHandle(), rcf.sharedClass.getName()); + GDIUtil.DestroyWindowClass0(rcf.sharedClass.getHInstance(), rcf.sharedClass.getName(), rcf.sharedClass.getHDispThreadContext()); rcf.sharedClass = null; rcf.sharedRefCount = 0; - rcf.classIter = 0; + rcf.classIter = 0; if(DEBUG) { - System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+" shutdownSharedClasses : "+rcf.sharedClass); + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+": shutdownSharedClasses : "+rcf.sharedClass); } + } else if(DEBUG) { + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+": null"); } } } } } - public RegisteredClassFactory(String classBaseName, long wndProc) { + /** Application handle. */ + public static long getHInstance() { return hInstance; } + + public RegisteredClassFactory(final String classBaseName, final long wndProc, final boolean useDummyDispatchThread, final long iconSmallHandle, final long iconBigHandle) { this.classBaseName = classBaseName; this.wndProc = wndProc; + this.useDummyDispatchThread = useDummyDispatchThread; + this.iconSmallHandle = iconSmallHandle; + this.iconBigHandle = iconBigHandle; synchronized(registeredFactories) { registeredFactories.add(this); } @@ -80,23 +110,28 @@ public class RegisteredClassFactory { if( null != sharedClass ) { throw new InternalError("Error ("+sharedRefCount+"): SharedClass not null: "+sharedClass); } - long hInstance = GDI.GetApplicationHandle(); - if( 0 == hInstance ) { - throw new NativeWindowException("Error: Null ModuleHandle for Application"); - } String clazzName = null; boolean registered = false; - final int classIterMark = classIter - 1; + final int classIterMark = classIter - 1; while ( !registered && classIterMark != classIter ) { // Retry with next clazz name, this could happen if more than one JVM is running clazzName = classBaseName + classIter; classIter++; - registered = GDIUtil.CreateWindowClass(hInstance, clazzName, wndProc); + registered = GDIUtil.CreateWindowClass0(hInstance, clazzName, wndProc, iconSmallHandle, iconBigHandle); } if( !registered ) { throw new NativeWindowException("Error: Could not create WindowClass: "+clazzName); } - sharedClass = new RegisteredClass(hInstance, clazzName); + final long hDispatchThread; + if( useDummyDispatchThread ) { + hDispatchThread = GDIUtil.CreateDummyDispatchThread0(); + if( 0 == hDispatchThread ) { + throw new NativeWindowException("Error: Could not create DDT "+clazzName); + } + } else { + hDispatchThread = 0; + } + sharedClass = new RegisteredClass(hInstance, clazzName, hDispatchThread); if(DEBUG) { System.err.println("RegisteredClassFactory getSharedClass ("+sharedRefCount+") initialized: "+sharedClass); } @@ -121,7 +156,7 @@ public class RegisteredClassFactory { throw new InternalError("Error ("+sharedRefCount+"): SharedClass is null"); } if( 0 == sharedRefCount ) { - GDIUtil.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); + GDIUtil.DestroyWindowClass0(sharedClass.getHInstance(), sharedClass.getName(), sharedClass.getHDispThreadContext()); if(DEBUG) { System.err.println("RegisteredClassFactory releaseSharedClass ("+sharedRefCount+") released: "+sharedClass); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java index 4f8cff8c5..0ac3d4a2e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Capabilities.java @@ -35,7 +35,7 @@ import javax.media.nativewindow.VisualIDHolder; public class X11Capabilities extends Capabilities { final private XVisualInfo xVisualInfo; // maybe null if !onscreen - public X11Capabilities(XVisualInfo xVisualInfo) { + public X11Capabilities(final XVisualInfo xVisualInfo) { super(); this.xVisualInfo = xVisualInfo; } @@ -49,7 +49,7 @@ public class X11Capabilities extends Capabilities { public Object clone() { try { return super.clone(); - } catch (RuntimeException e) { + } catch (final RuntimeException e) { throw new NativeWindowException(e); } } @@ -59,7 +59,7 @@ public class X11Capabilities extends Capabilities { final public boolean hasXVisualInfo() { return null!=xVisualInfo; } @Override - final public int getVisualID(VIDType type) throws NativeWindowException { + final public int getVisualID(final VIDType type) throws NativeWindowException { switch(type) { case INTRINSIC: case NATIVE: diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java index 55a29dd5e..7e61ba6d0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java @@ -14,47 +14,57 @@ import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { /** - * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, - * not the actual dummy surface width. + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. * The latter is platform specific and small - * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, * not the actual dummy surface height, * The latter is platform specific and small */ - public X11DummyUpstreamSurfaceHook(int width, int height) { + public X11DummyUpstreamSurfaceHook(final int width, final int height) { super(width, height); } - + @Override - public final void create(ProxySurface s) { + public final void create(final ProxySurface s) { final X11GraphicsConfiguration cfg = (X11GraphicsConfiguration) s.getGraphicsConfiguration(); final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen(); final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice(); - if(0 == device.getHandle()) { - device.open(); - s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); - } - if( 0 == s.getSurfaceHandle() ) { - final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64); - if(0 == windowHandle) { - throw new NativeWindowException("Creating dummy window failed w/ "+cfg); + device.lock(); + try { + if(0 == device.getHandle()) { + device.open(); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + if( 0 == s.getSurfaceHandle() ) { + final long windowHandle = X11Lib.CreateWindow(0, device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64, false, false); + if(0 == windowHandle) { + throw new NativeWindowException("Creating dummy window failed w/ "+cfg); + } + s.setSurfaceHandle(windowHandle); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } - s.setSurfaceHandle(windowHandle); - s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } finally { + device.unlock(); } - s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); } - + @Override - public final void destroy(ProxySurface s) { + public final void destroy(final ProxySurface s) { if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { final X11GraphicsDevice device = (X11GraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); if( 0 == s.getSurfaceHandle() ) { throw new InternalError("Owns upstream surface, but no X11 window: "+s); } - X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle()); - s.setSurfaceHandle(0); - s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + device.lock(); + try { + X11Lib.DestroyWindow(device.getHandle(), s.getSurfaceHandle()); + s.setSurfaceHandle(0); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } finally { + device.unlock(); + } } } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index b11dd1df1..e12c3fd13 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -47,12 +47,13 @@ import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { public static void registerFactory() { GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, CapabilitiesImmutable.class, new X11GraphicsConfigurationFactory()); - } + } private X11GraphicsConfigurationFactory() { } - + + @Override protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, final CapabilitiesChooser chooser, final AbstractGraphicsScreen screen, final int nativeVisualID) throws IllegalArgumentException, NativeWindowException { if(!(screen instanceof X11GraphicsScreen)) { @@ -71,15 +72,15 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor return res; } - public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, int visualID) + public static XVisualInfo getXVisualInfo(final AbstractGraphicsScreen screen, final int visualID) { - XVisualInfo xvi_temp = XVisualInfo.create(); + final XVisualInfo xvi_temp = XVisualInfo.create(); xvi_temp.setVisualid(visualID); xvi_temp.setScreen(screen.getIndex()); - int num[] = { -1 }; - long display = screen.getDevice().getHandle(); + final int num[] = { -1 }; + final long display = screen.getDevice().getHandle(); - XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); + final XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); if(xvis==null || num[0]<1) { return null; @@ -88,28 +89,28 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor return XVisualInfo.create(xvis[0]); } - public static XVisualInfo getXVisualInfo(AbstractGraphicsScreen screen, CapabilitiesImmutable capabilities) + public static XVisualInfo getXVisualInfo(final AbstractGraphicsScreen screen, final CapabilitiesImmutable capabilities) { - XVisualInfo xv = getXVisualInfoImpl(screen, capabilities, 4 /* TrueColor */); + final XVisualInfo xv = getXVisualInfoImpl(screen, capabilities, 4 /* TrueColor */); if(null!=xv) return xv; return getXVisualInfoImpl(screen, capabilities, 5 /* DirectColor */); } - private static XVisualInfo getXVisualInfoImpl(AbstractGraphicsScreen screen, CapabilitiesImmutable capabilities, int c_class) + private static XVisualInfo getXVisualInfoImpl(final AbstractGraphicsScreen screen, final CapabilitiesImmutable capabilities, final int c_class) { XVisualInfo ret = null; - int[] num = { -1 }; + final int[] num = { -1 }; - XVisualInfo vinfo_template = XVisualInfo.create(); + final XVisualInfo vinfo_template = XVisualInfo.create(); vinfo_template.setScreen(screen.getIndex()); vinfo_template.setC_class(c_class); - long display = screen.getDevice().getHandle(); + final long display = screen.getDevice().getHandle(); - XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); + final XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); XVisualInfo best=null; - int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); + final int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); for (int i = 0; vinfos!=null && i < num[0]; i++) { - if ( best == null || + if ( best == null || best.getDepth() < vinfos[i].getDepth() ) { best = vinfos[i]; diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 93b7f3487..2414248b4 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -34,6 +34,7 @@ package jogamp.nativewindow.x11; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; @@ -42,22 +43,27 @@ import javax.media.nativewindow.NativeWindowFactory; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; import com.jogamp.common.util.LongObjectHashMap; +import com.jogamp.common.util.PropertyAccess; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; /** * Contains a thread safe X11 utility to retrieve display connections. */ -public class X11Util { - /** +public class X11Util implements ToolkitProperties { + public static final boolean DEBUG = Debug.debug("X11Util"); + + /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 - * <p> + * <p> * It is observed that ATI X11 drivers, eg. - * <ul> + * <ul> * <li>fglrx 8.78.6,</li> * <li>fglrx 11.08/8.881 and </li> * <li>fglrx 11.11/8.911</li> - * </ul> + * </ul> * are quite sensitive to multiple Display connections. * </p> * <p> @@ -70,33 +76,39 @@ public class X11Util { * See also native test: jogl/test-native/displayMultiple02.c * </p> * <p> - * Workaround is to not close them at all if driver vendor is ATI. + * Workaround is to not close them at all if driver vendor is ATI + * during operation. + * </p> + * <p> + * With ATI X11 drivers all connections must be closed at JVM shutdown, + * otherwise a SIGSEGV (after JVM safepoint) will be caused. * </p> */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG", true); - /** Value is <code>true</code>, best 'stable' results if always using XInitThreads(). */ - public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; - - /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ - public static final boolean HAS_XLOCKDISPLAY_BUG = true; - - public static final boolean DEBUG = Debug.debug("X11Util"); + /** See {@link #ATI_HAS_XCLOSEDISPLAY_BUG}. */ + public static final boolean HAS_XCLOSEDISPLAY_BUG = Debug.isPropertyDefined("nativewindow.debug.X11Util.HAS_XCLOSEDISPLAY_BUG", true); + + /** + * See Bug 623 - https://jogamp.org/bugzilla/show_bug.cgi?id=623 + */ + public static final boolean ATI_HAS_MULTITHREADING_BUG = !Debug.isPropertyDefined("nativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG", true); + public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true); public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); private static String nullDisplayName = null; - private static boolean isX11LockAvailable = false; - private static boolean requiresX11Lock = true; private static volatile boolean isInit = false; - private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues + private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues, or GLRendererQuirks.DontCloseX11Display + private static boolean hasThreadingIssues = false; // ATI/AMD X11 driver issues - private static int setX11ErrorHandlerRecCount = 0; - private static Object setX11ErrorHandlerLock = new Object(); + private static final Object setX11ErrorHandlerLock = new Object(); + private static final String X11_EXTENSION_ATIFGLRXDRI = "ATIFGLRXDRI"; + private static final String X11_EXTENSION_ATIFGLEXTENSION = "ATIFGLEXTENSION"; - /** * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties */ public static void initSingleton() { if(!isInit) { @@ -104,59 +116,84 @@ public class X11Util { if(!isInit) { isInit = true; if(DEBUG) { - System.out.println("X11UtilUtil.initSingleton()"); + System.out.println("X11Util.initSingleton()"); } if(!NWJNILibLoader.loadNativeWindow("x11")) { throw new NativeWindowException("NativeWindow X11 native library load error."); } - - final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED ; - final boolean isXInitThreadsOK = initialize0( callXInitThreads, XERROR_STACKDUMP); - isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; - - final long dpy = X11Lib.XOpenDisplay(null); + + final boolean isInitOK = initialize0( XERROR_STACKDUMP ); + + final boolean hasX11_EXTENSION_ATIFGLRXDRI, hasX11_EXTENSION_ATIFGLEXTENSION; + final long dpy = X11Lib.XOpenDisplay(PropertyAccess.getProperty("nativewindow.x11.display.default", true)); if(0 != dpy) { if(XSYNC_ENABLED) { X11Lib.XSynchronize(dpy, true); - } + } try { nullDisplayName = X11Lib.XDisplayString(dpy); + hasX11_EXTENSION_ATIFGLRXDRI = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLRXDRI); + hasX11_EXTENSION_ATIFGLEXTENSION = X11Lib.QueryExtension(dpy, X11_EXTENSION_ATIFGLEXTENSION); } finally { X11Lib.XCloseDisplay(dpy); } } else { nullDisplayName = "nil"; + hasX11_EXTENSION_ATIFGLRXDRI = false; + hasX11_EXTENSION_ATIFGLEXTENSION = false; + } + final boolean isATIFGLRX = hasX11_EXTENSION_ATIFGLRXDRI || hasX11_EXTENSION_ATIFGLEXTENSION ; + hasThreadingIssues = ATI_HAS_MULTITHREADING_BUG && isATIFGLRX; + if ( !markAllDisplaysUnclosable ) { + markAllDisplaysUnclosable = ( ATI_HAS_XCLOSEDISPLAY_BUG && isATIFGLRX ) || HAS_XCLOSEDISPLAY_BUG; } - + if(DEBUG) { - System.err.println("X11Util requiresX11Lock "+requiresX11Lock+ - ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ - ", isX11LockAvailable "+isX11LockAvailable+ - ", X11 Display(NULL) <"+nullDisplayName+">"+ - ", XSynchronize Enabled: "+XSYNC_ENABLED); + System.err.println("X11Util.initSingleton(): OK "+isInitOK+"]"+ + ",\n\t X11 Display(NULL) <"+nullDisplayName+">"+ + ",\n\t XSynchronize Enabled: " + XSYNC_ENABLED+ + ",\n\t X11_EXTENSION_ATIFGLRXDRI " + hasX11_EXTENSION_ATIFGLRXDRI+ + ",\n\t X11_EXTENSION_ATIFGLEXTENSION " + hasX11_EXTENSION_ATIFGLEXTENSION+ + ",\n\t requiresToolkitLock "+requiresToolkitLock()+ + ",\n\t hasThreadingIssues "+hasThreadingIssues()+ + ",\n\t markAllDisplaysUnclosable "+getMarkAllDisplaysUnclosable() + ); // Thread.dumpStack(); } } } } } - - /** + + // not exactly thread safe, but good enough for our purpose, + // which is to tag a NamedDisplay uncloseable after creation. + private static Object globalLock = new Object(); + private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name + private static List<NamedDisplay> openDisplayList = new ArrayList<NamedDisplay>(); // open, no close attempt + private static List<NamedDisplay> reusableDisplayList = new ArrayList<NamedDisplay>(); // close attempt, marked uncloseable, for reuse + private static List<NamedDisplay> pendingDisplayList = new ArrayList<NamedDisplay>(); // all open (close attempt or reusable) in creation order + private static final HashMap<String /* displayName */, Boolean> displayXineramaEnabledMap = new HashMap<String, Boolean>(); + + /** * Cleanup resources. * <p> * Called by {@link NativeWindowFactory#shutdown()} * </p> + * @see ToolkitProperties */ public static void shutdown() { if(isInit) { synchronized(X11Util.class) { - if(isInit) { + if(isInit) { final boolean isJVMShuttingDown = NativeWindowFactory.isJVMShuttingDown() ; - if(DEBUG || openDisplayMap.size() > 0 || reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0) { + if( DEBUG || + ( ( openDisplayMap.size() > 0 || reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) && + ( reusableDisplayList.size() != pendingDisplayList.size() || !markAllDisplaysUnclosable ) + ) ) { System.err.println("X11Util.Display: Shutdown (JVM shutdown: "+isJVMShuttingDown+ ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ ", reusable (open, marked uncloseable): "+reusableDisplayList.size()+ - ", pending (post closing): "+pendingDisplayList.size()+ + ", pending (open in creation order): "+pendingDisplayList.size()+ ")"); if(DEBUG) { Thread.dumpStack(); @@ -164,21 +201,24 @@ public class X11Util { if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); } - if( reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) { - X11Util.dumpPendingDisplayConnections(); + if(DEBUG) { + if( reusableDisplayList.size() > 0 || pendingDisplayList.size() > 0 ) { + X11Util.dumpPendingDisplayConnections(); + } } } - - synchronized(globalLock) { - // Only at JVM shutdown time, since AWT impl. seems to - // dislike closing of X11 Display's (w/ ATI driver). - if( isJVMShuttingDown ) { - isInit = false; - closePendingDisplayConnections(); + + // Only at JVM shutdown time, since AWT impl. seems to + // dislike closing of X11 Display's (w/ ATI driver). + if( isJVMShuttingDown ) { + synchronized(globalLock) { + isInit = false; + closePendingDisplayConnections(); openDisplayList.clear(); reusableDisplayList.clear(); pendingDisplayList.clear(); openDisplayMap.clear(); + displayXineramaEnabledMap.clear(); shutdown0(); } } @@ -187,53 +227,52 @@ public class X11Util { } } - public static synchronized boolean isNativeLockAvailable() { - return isX11LockAvailable; + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean requiresToolkitLock() { + return true; // JAWT locking: yes, instead of native X11 locking w use a recursive lock per display connection. } - public static synchronized boolean requiresToolkitLock() { - return requiresX11Lock; + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { + return hasThreadingIssues; // JOGL impl. may utilize special locking "somewhere" } - public static void setX11ErrorHandler(boolean onoff, boolean quiet) { + public static void setX11ErrorHandler(final boolean onoff, final boolean quiet) { synchronized(setX11ErrorHandlerLock) { - if(onoff) { - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(true, quiet); - } - setX11ErrorHandlerRecCount++; - } else { - if(0 >= setX11ErrorHandlerRecCount) { - throw new InternalError(); - } - setX11ErrorHandlerRecCount--; - if(0==setX11ErrorHandlerRecCount) { - setX11ErrorHandler0(false, false); - } - } + setX11ErrorHandler0(onoff, quiet); } } public static String getNullDisplayName() { return nullDisplayName; } - + + public static void markAllDisplaysUnclosable() { + synchronized(globalLock) { + markAllDisplaysUnclosable = true; + for(int i=0; i<openDisplayList.size(); i++) { + openDisplayList.get(i).setUncloseable(true); + } + for(int i=0; i<reusableDisplayList.size(); i++) { + reusableDisplayList.get(i).setUncloseable(true); + } + for(int i=0; i<pendingDisplayList.size(); i++) { + pendingDisplayList.get(i).setUncloseable(true); + } + } + } + public static boolean getMarkAllDisplaysUnclosable() { return markAllDisplaysUnclosable; } - public static void setMarkAllDisplaysUnclosable(boolean v) { - markAllDisplaysUnclosable = v; - } - - private X11Util() {} - // not exactly thread safe, but good enough for our purpose, - // which is to tag a NamedDisplay uncloseable after creation. - private static Object globalLock = new Object(); - private static LongObjectHashMap openDisplayMap = new LongObjectHashMap(); // handle -> name - private static List<NamedDisplay> openDisplayList = new ArrayList<NamedDisplay>(); - private static List<NamedDisplay> reusableDisplayList = new ArrayList<NamedDisplay>(); - private static List<NamedDisplay> pendingDisplayList = new ArrayList<NamedDisplay>(); + private X11Util() {} public static class NamedDisplay { final String name; @@ -243,7 +282,7 @@ public class X11Util { boolean unCloseable; Throwable creationStack; - protected NamedDisplay(String name, long handle) { + protected NamedDisplay(final String name, final long handle) { this.name=name; this.handle=handle; this.refCount=0; @@ -261,58 +300,58 @@ public class X11Util { } } + @Override public final int hashCode() { return hash32; } - - public final boolean equals(Object obj) { + + @Override + public final boolean equals(final Object obj) { if(this == obj) { return true; } if(obj instanceof NamedDisplay) { return handle == ((NamedDisplay) obj).handle; } return false; } - + public final void addRef() { refCount++; } public final void removeRef() { refCount--; } - + public final String getName() { return name; } public final long getHandle() { return handle; } public final int getRefCount() { return refCount; } - public final void setUncloseable(boolean v) { unCloseable = v; } + public final void setUncloseable(final boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } public final Throwable getCreationStack() { return creationStack; } @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override public String toString() { return "NamedX11Display["+name+", 0x"+Long.toHexString(handle)+", refCount "+refCount+", unCloseable "+unCloseable+"]"; } } /** - * Closing pending Display connections in reverse order. + * Closing pending Display connections in original creation order, if {@link #getMarkAllDisplaysUnclosable()} is true. * * @return number of closed Display connections */ - public static int closePendingDisplayConnections() { + private static int closePendingDisplayConnections() { int num=0; synchronized(globalLock) { - if(DEBUG) { - System.err.println("X11Util: Closing Pending X11 Display Connections in order of their creation: "+pendingDisplayList.size()); - } - for(int i=0; i<pendingDisplayList.size(); i++) { - NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); + if( getMarkAllDisplaysUnclosable() ) { + for(int i=0; i<pendingDisplayList.size(); i++) { + final NamedDisplay ndpy = pendingDisplayList.get(i); + if(DEBUG) { + final boolean closeAttempted = !openDisplayMap.containsKey(ndpy.getHandle()); + System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy+" - closeAttempted "+closeAttempted); + } + XCloseDisplay(ndpy.getHandle()); + num++; + } if(DEBUG) { - System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy); + System.err.println("X11Util.closePendingDisplayConnections(): Closed "+num+" pending display connections"); } - XCloseDisplay(ndpy.getHandle()); - num++; } } return num; @@ -323,15 +362,15 @@ public class X11Util { return openDisplayList.size(); } } - + public static void dumpOpenDisplayConnections() { synchronized(globalLock) { System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size()); for(int i=0; i<openDisplayList.size(); i++) { - NamedDisplay ndpy = openDisplayList.get(i); + final NamedDisplay ndpy = openDisplayList.get(i); System.err.println("X11Util: Open["+i+"]: "+ndpy); if(null!=ndpy) { - Throwable t = ndpy.getCreationStack(); + final Throwable t = ndpy.getCreationStack(); if(null!=t) { t.printStackTrace(); } @@ -339,7 +378,7 @@ public class X11Util { } } } - + public static int getReusableDisplayConnectionNumber() { synchronized(globalLock) { return reusableDisplayList.size(); @@ -356,10 +395,10 @@ public class X11Util { synchronized(globalLock) { System.err.println("X11Util: Reusable X11 Display Connections: "+reusableDisplayList.size()); for(int i=0; i<reusableDisplayList.size(); i++) { - NamedDisplay ndpy = (NamedDisplay) reusableDisplayList.get(i); + final NamedDisplay ndpy = reusableDisplayList.get(i); System.err.println("X11Util: Reusable["+i+"]: "+ndpy); if(null!=ndpy) { - Throwable t = ndpy.getCreationStack(); + final Throwable t = ndpy.getCreationStack(); if(null!=t) { t.printStackTrace(); } @@ -367,10 +406,10 @@ public class X11Util { } System.err.println("X11Util: Pending X11 Display Connections (creation order): "+pendingDisplayList.size()); for(int i=0; i<pendingDisplayList.size(); i++) { - NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); + final NamedDisplay ndpy = pendingDisplayList.get(i); System.err.println("X11Util: Pending["+i+"]: "+ndpy); if(null!=ndpy) { - Throwable t = ndpy.getCreationStack(); + final Throwable t = ndpy.getCreationStack(); if(null!=t) { t.printStackTrace(); } @@ -379,7 +418,7 @@ public class X11Util { } } - public static boolean markDisplayUncloseable(long handle) { + public static boolean markDisplayUncloseable(final long handle) { NamedDisplay ndpy; synchronized(globalLock) { ndpy = (NamedDisplay) openDisplayMap.get(handle); @@ -397,8 +436,8 @@ public class X11Util { NamedDisplay namedDpy = null; name = validateDisplayName(name); boolean reused = false; - - synchronized(globalLock) { + + synchronized(globalLock) { for(int i=0; i<reusableDisplayList.size(); i++) { if(reusableDisplayList.get(i).getName().equals(name)) { namedDpy = reusableDisplayList.remove(i); @@ -431,11 +470,9 @@ public class X11Util { return namedDpy.getHandle(); } - public static void closeDisplay(long handle) { - NamedDisplay namedDpy; - + public static void closeDisplay(final long handle) { synchronized(globalLock) { - namedDpy = (NamedDisplay) openDisplayMap.remove(handle); + final NamedDisplay namedDpy = (NamedDisplay) openDisplayMap.remove(handle); if(null==namedDpy) { X11Util.dumpPendingDisplayConnections(); throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped. Thread "+Thread.currentThread().getName()); @@ -444,38 +481,43 @@ public class X11Util { X11Util.dumpPendingDisplayConnections(); throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") Mapping error: "+namedDpy+". Thread "+Thread.currentThread().getName()); } - + namedDpy.removeRef(); if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } - - if(!namedDpy.isUncloseable()) { + + if( markAllDisplaysUnclosable ) { + // if set-mark 'slipped' this one .. just to be safe! + namedDpy.setUncloseable(true); + } + if( !namedDpy.isUncloseable() ) { XCloseDisplay(namedDpy.getHandle()); pendingDisplayList.remove(namedDpy); } else { // for reuse + X11Lib.XSync(namedDpy.getHandle(), true); // flush output buffer and discard all events reusableDisplayList.add(namedDpy); } - + if(DEBUG) { System.err.println("X11Util.Display: Closed (real: "+(!namedDpy.isUncloseable())+") "+namedDpy+". Thread "+Thread.currentThread().getName()); - } + } } } - public static NamedDisplay getNamedDisplay(long handle) { + public static NamedDisplay getNamedDisplay(final long handle) { synchronized(globalLock) { return (NamedDisplay) openDisplayMap.get(handle); } } - /** + /** * @return If name is null, it returns the previous queried NULL display name, * otherwise the name. */ - public static String validateDisplayName(String name) { + public static String validateDisplayName(final String name) { return ( null == name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) ? getNullDisplayName() : name ; } - public static String validateDisplayName(String name, long handle) { + public static String validateDisplayName(String name, final long handle) { if( ( null==name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) && 0!=handle) { name = X11Lib.XDisplayString(handle); } @@ -488,54 +530,61 @@ public class X11Util { ** *******************************/ - public static long XOpenDisplay(String arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - long handle = X11Lib.XOpenDisplay(arg0); - if(XSYNC_ENABLED && 0 != handle) { - X11Lib.XSynchronize(handle, true); - } - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - // Thread.dumpStack(); - } - return handle; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + public static long XOpenDisplay(final String arg0) { + final long handle = X11Lib.XOpenDisplay(arg0); + if(XSYNC_ENABLED && 0 != handle) { + X11Lib.XSynchronize(handle, true); } + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); + } + return handle; } - public static int XCloseDisplay(long display) { - NativeWindowFactory.getDefaultToolkitLock().lock(); + public static int XCloseDisplay(final long display) { + if(TRACE_DISPLAY_LIFECYCLE) { + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); + } + int res = -1; try { - if(TRACE_DISPLAY_LIFECYCLE) { - System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - // Thread.dumpStack(); - } - int res = -1; - X11Util.setX11ErrorHandler(true, DEBUG ? false : true); - try { - res = X11Lib.XCloseDisplay(display); - } catch (Exception ex) { - System.err.println("X11Util: Catched Exception:"); - ex.printStackTrace(); - } finally { - X11Util.setX11ErrorHandler(false, false); - } - return res; - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); + res = X11Lib.XCloseDisplay(display); + } catch (final Exception ex) { + System.err.println("X11Util: Caught exception:"); + ex.printStackTrace(); } + return res; } static volatile boolean XineramaFetched = false; static long XineramaLibHandle = 0; static long XineramaQueryFunc = 0; - - public static boolean XineramaIsEnabled(long display) { - if(0==display) { - throw new IllegalArgumentException("Display NULL"); + + public static boolean XineramaIsEnabled(final X11GraphicsDevice device) { + if(null == device) { + throw new IllegalArgumentException("X11 Display device is NULL"); } + device.lock(); + try { + return XineramaIsEnabled(device.getHandle()); + } finally { + device.unlock(); + } + } + + public static boolean XineramaIsEnabled(final long displayHandle) { + if( 0 == displayHandle ) { + throw new IllegalArgumentException("X11 Display handle is NULL"); + } + final String displayName = X11Lib.XDisplayString(displayHandle); + synchronized(displayXineramaEnabledMap) { + final Boolean b = displayXineramaEnabledMap.get(displayName); + if(null != b) { + return b.booleanValue(); + } + } + final boolean res; if(!XineramaFetched) { // volatile: ok synchronized(X11Util.class) { if( !XineramaFetched ) { @@ -548,22 +597,27 @@ public class X11Util { } } if(0!=XineramaQueryFunc) { - final boolean res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, display); + res = X11Lib.XineramaIsEnabled(XineramaQueryFunc, displayHandle); + } else { if(DEBUG) { - System.err.println("XineramaIsEnabled: "+res); + System.err.println("XineramaIsEnabled: Couldn't bind to Xinerama - lib 0x"+Long.toHexString(XineramaLibHandle)+ + "query 0x"+Long.toHexString(XineramaQueryFunc)); } - return res; - } else if(DEBUG) { - System.err.println("XineramaIsEnabled: Couldn't bind to Xinerama - lib 0x"+Long.toHexString(XineramaLibHandle)+ - "query 0x"+Long.toHexString(XineramaQueryFunc)); + res = false; } - return false; + synchronized(displayXineramaEnabledMap) { + if(DEBUG) { + System.err.println("XineramaIsEnabled Cache: Display "+displayName+" (0x"+Long.toHexString(displayHandle)+") -> "+res); + } + displayXineramaEnabledMap.put(displayName, Boolean.valueOf(res)); + } + return res; } - + private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI - - private static native boolean initialize0(boolean firstUIActionOnProcess, boolean debug); + + private static native boolean initialize0(boolean debug); private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java index 1de03e8be..6b606df97 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -1,22 +1,22 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A @@ -59,16 +59,17 @@ import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory { - + public static void registerFactory() { GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.awt.AWTGraphicsDevice.class, CapabilitiesImmutable.class, new X11AWTGraphicsConfigurationFactory()); - } + } private X11AWTGraphicsConfigurationFactory() { } + @Override protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, final int nativeVisualID) { if (absScreen != null && !(absScreen instanceof AWTGraphicsScreen)) { throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects"); @@ -79,19 +80,19 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen, nativeVisualID); } - + public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic( - CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen, int nativeVisualID) { + CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, final AWTGraphicsScreen awtScreen, final int nativeVisualID) { if(DEBUG) { System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen); } - + final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); - + final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); final long displayHandle; - boolean owner = false; + final boolean owner; if(0==displayHandleAWT) { displayHandle = X11Util.openDisplay(null); owner = true; @@ -101,8 +102,8 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac } else { /** * Using the AWT display handle works fine with NVidia. - * However we experienced different results w/ AMD drivers, - * some work, but some behave erratic. + * However we experienced different results w/ AMD drivers, + * some work, but some behave erratic. * I.e. hangs in XQueryExtension(..) via X11GraphicsScreen. */ final String displayName = X11Lib.XDisplayString(displayHandleAWT); @@ -112,15 +113,14 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println(getThreadName()+" - X11AWTGraphicsConfigurationFactory: AWT dpy "+displayName+" / "+toHexString(displayHandleAWT)+", create X11 display "+toHexString(displayHandle)); } } - final ToolkitLock lock = owner ? - NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock - NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle); - final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); + // Global JAWT lock required - No X11 resource locking due to private display connection + final ToolkitLock lock = NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT); + final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); if(DEBUG) { System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen); } - + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device, capsChosen); AbstractGraphicsConfiguration aConfig = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen, nativeVisualID); if (aConfig == null) { @@ -130,7 +130,7 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac System.err.println("X11AWTGraphicsConfigurationFactory: chosen config: "+aConfig); // Thread.dumpStack(); } - + // // Match the X11/GL Visual with AWT: // - choose a config AWT agnostic and then @@ -138,12 +138,12 @@ public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFac // // The resulting GraphicsConfiguration has to be 'forced' on the AWT native peer, // ie. returned by GLCanvas's getGraphicsConfiguration() befor call by super.addNotify(). - // + // final GraphicsConfiguration[] configs = device.getConfigurations(); int visualID = aConfig.getVisualID(VIDType.NATIVE); if(VisualIDHolder.VID_UNDEFINED != visualID) { for (int i = 0; i < configs.length; i++) { - GraphicsConfiguration gc = configs[i]; + final GraphicsConfiguration gc = configs[i]; if (gc != null) { if (X11SunJDKReflection.graphicsConfigurationGetVisualID(gc) == visualID) { if(DEBUG) { |