diff options
Diffstat (limited to 'src/nativewindow')
46 files changed, 1949 insertions, 759 deletions
diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java index 784343c5a..1930bdda3 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -50,7 +51,7 @@ public interface AbstractGraphicsConfiguration extends Cloneable { /** * Return the capabilities reflecting this graphics configuration, - * which may differ from the capabilites used to choose this configuration. + * which may differ from the capabilities used to choose this configuration. * * @return An immutable instance of the Capabilities to avoid mutation by * the user. @@ -61,7 +62,7 @@ public interface AbstractGraphicsConfiguration extends Cloneable { * Return the capabilities used to choose this graphics configuration. * * These may be used to reconfigure the NativeWindow in case - * the device changes in a multi screen environment. + * the device changes in a multiple screen environment. * * @return An immutable instance of the Capabilities to avoid mutation by * the user. @@ -69,10 +70,10 @@ public interface AbstractGraphicsConfiguration extends Cloneable { public CapabilitiesImmutable getRequestedCapabilities(); /** - * In case this instance already reflects a native configuration, - * return this one. - * Otherwise return the encapsuled native configuration, - * as it shall be included e.g. in the AWT case. + * In case the implementation utilizes a delegation pattern to wrap abstract toolkits, + * this method shall return the native {@link AbstractGraphicsConfiguration}, + * otherwise this instance. + * @see NativeSurface#getGraphicsConfiguration() */ public AbstractGraphicsConfiguration getNativeGraphicsConfiguration(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 83b437612..fa25c214f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -110,14 +110,15 @@ public interface AbstractGraphicsDevice extends Cloneable { public void unlock(); /** - * Optionally closing the device.<br> - * The default implementation is a NOP operation, returning false.<br> + * Optionally closing the device. + * <p> + * The default implementation is a <code>NOP</code>, just setting the handle to <code>null</code>. + * </p> * The specific implementing, ie {@link javax.media.nativewindow.x11.X11GraphicsDevice}, * shall have a enable/disable like {@link javax.media.nativewindow.x11.X11GraphicsDevice#setCloseDisplay(boolean, boolean)},<br> * which shall be invoked at creation time to determine ownership/role of freeing the resource.<br> * - * @return true if a specialized closing operation was successfully issued, otherwise false, - * ie no native closing operation was issued, which doesn't imply an error at all. + * @return true if the handle was not <code>null</code>, otherwise false. */ public boolean close(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java index ffa8bfae6..3eb7a6c9a 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java @@ -84,8 +84,6 @@ public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphics * The use case for setting the Capabilities at a later time is * a change of the graphics device in a multi-screen environment.<br> * - * The objects reference is being used. - * * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ protected void setChosenCapabilities(CapabilitiesImmutable capsChosen) { diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index c2aa6fae9..187959a67 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -46,7 +46,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice /** * Create an instance with the system default {@link ToolkitLock}, - * gathered via {@link NativeWindowFactory#createDefaultToolkitLock()}. + * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String)}. * @param type */ public DefaultGraphicsDevice(String type, String connection, int unitID) { @@ -55,12 +55,12 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = 0; - setToolkitLock( NativeWindowFactory.getDefaultToolkitLock(type) ); + this.toolkitLock = NativeWindowFactory.getDefaultToolkitLock(type); } /** * Create an instance with the system default {@link ToolkitLock}. - * gathered via {@link NativeWindowFactory#createDefaultToolkitLock()}. + * gathered via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. * @param type * @param handle */ @@ -70,7 +70,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = handle; - setToolkitLock( NativeWindowFactory.createDefaultToolkitLock(type, handle) ); + this.toolkitLock = NativeWindowFactory.createDefaultToolkitLock(type, handle); } /** @@ -85,7 +85,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = handle; - setToolkitLock( locker ); + this.toolkitLock = null != locker ? locker : NativeWindowFactoryImpl.getNullToolkitLock(); } @Override @@ -140,6 +140,10 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } public boolean close() { + if(0 != handle) { + handle = 0; + return true; + } return false; } @@ -152,10 +156,21 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice * Set the internal ToolkitLock, which is used within the * {@link #lock()} and {@link #unlock()} implementation. * + * <p> + * The current ToolkitLock is being locked/unlocked while swapping the reference, + * ensuring no concurrent access can occur during the swap. + * </p> + * * @param locker the ToolkitLock, if null, {@link jogamp.nativewindow.NullToolkitLock} is being used */ protected void setToolkitLock(ToolkitLock locker) { - this.toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + final ToolkitLock _toolkitLock = toolkitLock; + _toolkitLock.lock(); + try { + toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + } finally { + _toolkitLock.unlock(); + } } /** diff --git a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index fa3923dcf..259644467 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -40,7 +40,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; - /** * Provides the mechanism by which the graphics configuration for a * window can be chosen before the window is created. The graphics @@ -60,12 +59,34 @@ import java.util.Map; public abstract class GraphicsConfigurationFactory { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); - private static Map/*<Class, NativeWindowFactory>*/ registeredFactories = - Collections.synchronizedMap(new HashMap()); - private static Class abstractGraphicsDeviceClass; + private static Map<Class<?>, GraphicsConfigurationFactory> registeredFactories = + Collections.synchronizedMap(new HashMap<Class<?>, GraphicsConfigurationFactory>()); + private static Class<?> abstractGraphicsDeviceClass; static { - initialize(); + abstractGraphicsDeviceClass = javax.media.nativewindow.AbstractGraphicsDevice.class; + + // Register the default no-op factory for arbitrary + // AbstractGraphicsDevice implementations, including + // AWTGraphicsDevice instances -- the OpenGL binding will take + // care of handling AWTGraphicsDevices on X11 platforms (as + // well as X11GraphicsDevices in non-AWT situations) + registerFactory(abstractGraphicsDeviceClass, new DefaultGraphicsConfigurationFactoryImpl()); + + if (NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { + try { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (Exception e) { + throw new RuntimeException(e); + } + if(NativeWindowFactory.isAWTAvailable()) { + try { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.awt.X11AWTGraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (Exception e) { /* n/a */ } + } + } } protected static String getThreadName() { @@ -85,27 +106,6 @@ public abstract class GraphicsConfigurationFactory { protected GraphicsConfigurationFactory() { } - private static void initialize() { - abstractGraphicsDeviceClass = javax.media.nativewindow.AbstractGraphicsDevice.class; - - if (NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { - try { - GraphicsConfigurationFactory factory = (GraphicsConfigurationFactory) - ReflectionUtil.createInstance("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", null, - GraphicsConfigurationFactory.class.getClassLoader()); - registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, factory); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - // Register the default no-op factory for arbitrary - // AbstractGraphicsDevice implementations, including - // AWTGraphicsDevice instances -- the OpenGL binding will take - // care of handling AWTGraphicsDevices on X11 platforms (as - // well as X11GraphicsDevices in non-AWT situations) - registerFactory(abstractGraphicsDeviceClass, new DefaultGraphicsConfigurationFactoryImpl()); - } - /** Returns the factory for use with the given type of AbstractGraphicsDevice. */ public static GraphicsConfigurationFactory getFactory(AbstractGraphicsDevice device) { @@ -122,7 +122,7 @@ public abstract class GraphicsConfigurationFactory { * * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice */ - public static GraphicsConfigurationFactory getFactory(Class abstractGraphicsDeviceImplementor) + public static GraphicsConfigurationFactory getFactory(Class<?> abstractGraphicsDeviceImplementor) throws IllegalArgumentException, NativeWindowException { if (!(abstractGraphicsDeviceClass.isAssignableFrom(abstractGraphicsDeviceImplementor))) { @@ -130,10 +130,9 @@ public abstract class GraphicsConfigurationFactory { } GraphicsConfigurationFactory factory = null; - Class clazz = abstractGraphicsDeviceImplementor; + Class<?> clazz = abstractGraphicsDeviceImplementor; while (clazz != null) { - factory = - (GraphicsConfigurationFactory) registeredFactories.get(clazz); + factory = registeredFactories.get(clazz); if (factory != null) { if(DEBUG) { System.err.println("GraphicsConfigurationFactory.getFactory() "+abstractGraphicsDeviceImplementor+" -> "+factory); @@ -143,7 +142,7 @@ public abstract class GraphicsConfigurationFactory { clazz = clazz.getSuperclass(); } // Return the default - factory = (GraphicsConfigurationFactory)registeredFactories.get(abstractGraphicsDeviceClass); + factory = registeredFactories.get(abstractGraphicsDeviceClass); if(DEBUG) { System.err.println("GraphicsConfigurationFactory.getFactory() DEFAULT "+abstractGraphicsDeviceClass+" -> "+factory); } @@ -157,7 +156,7 @@ public abstract class GraphicsConfigurationFactory { * * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice */ - protected static void registerFactory(Class abstractGraphicsDeviceImplementor, GraphicsConfigurationFactory factory) + protected static void registerFactory(Class<?> abstractGraphicsDeviceImplementor, GraphicsConfigurationFactory factory) throws IllegalArgumentException { if (!(abstractGraphicsDeviceClass.isAssignableFrom(abstractGraphicsDeviceImplementor))) { diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java index e691ba8e6..e255dc051 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java @@ -118,6 +118,24 @@ public interface NativeSurface extends SurfaceUpdatedListener { */ public boolean surfaceSwap(); + /** Appends the given {@link SurfaceUpdatedListener} to the end of the list. */ + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l); + + /** + * Inserts the given {@link SurfaceUpdatedListener} at the + * specified position in the list.<br> + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). + * @param l The listener object to be inserted + * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 + */ + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; + + /** Remove the specified {@link SurfaceUpdatedListener} from the list. */ + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); + /** * Returns the handle to the surface for this NativeSurface. <P> * @@ -149,6 +167,11 @@ public interface NativeSurface extends SurfaceUpdatedListener { /** * Returns the graphics configuration corresponding to this window. + * <p> + * In case the implementation utilizes a delegation pattern to wrap abstract toolkits, + * this method shall return the native {@link AbstractGraphicsConfiguration} via {@link AbstractGraphicsConfiguration#getNativeGraphicsConfiguration()}. + * </p> + * @see AbstractGraphicsConfiguration#getNativeGraphicsConfiguration() * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ public AbstractGraphicsConfiguration getGraphicsConfiguration(); diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index 76ac72953..2bc352116 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -104,20 +104,26 @@ public interface NativeWindow extends NativeSurface { /** * @return the current x position of the top-left corner - * of the client area, hence excluding insets (window decorations).<br> + * of the client area relative to it's parent. + * Since the position reflects the client area, it does not include the insets. * @see #getInsets() */ public int getX(); /** * @return the current y position of the top-left corner - * of the client area, hence excluding insets (window decorations).<br> + * of the client area relative to it's parent. + * Since the position reflects the client area, it does not include the insets. * @see #getInsets() */ public int getY(); /** - * Returns the current absolute location of this window. + * Returns the current position of the top-left corner + * of the client area in screen coordinates. + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> * @param point if not null, * {@link javax.media.nativewindow.util.Point#translate(javax.media.nativewindow.util.Point)} * the passed {@link javax.media.nativewindow.util.Point} by this location on the screen and return it. @@ -126,4 +132,7 @@ public interface NativeWindow extends NativeSurface { */ public Point getLocationOnScreen(Point point); + /** Returns true if this native window owns the focus, otherwise false. */ + boolean hasFocus(); + } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index ef8876f50..c69b18b30 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -33,15 +33,20 @@ package javax.media.nativewindow; -import java.security.*; -import java.util.*; - -import com.jogamp.common.util.*; -import com.jogamp.common.os.Platform; - -import jogamp.nativewindow.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NativeWindowFactoryImpl; + +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.ReflectionUtil; /** Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the {@link NativeWindow} interface, @@ -75,20 +80,25 @@ public abstract class NativeWindowFactory { private static NativeWindowFactory defaultFactory; private static Map<Class<?>, NativeWindowFactory> registeredFactories; + private static Class<?> nativeWindowClass; private static String nativeWindowingTypePure; private static String nativeWindowingTypeCustom; private static boolean isAWTAvailable; - public static final String AWTComponentClassName = "java.awt.Component" ; - public static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; - public static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; - public static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; - public static final String GDIClassName = "jogamp.nativewindow.windows.GDI"; - public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; - public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; + + private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; + private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; + private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; + private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; + private static Class<?> jawtUtilClass; private static Method jawtUtilGetJAWTToolkitMethod; private static Method jawtUtilInitMethod; + + public static final String AWTComponentClassName = "java.awt.Component" ; + public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; + public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; + private static Class<?> x11JAWTToolkitLockClass; private static Constructor<?> x11JAWTToolkitLockConstructor; private static Class<?> x11ToolkitLockClass; @@ -132,16 +142,18 @@ public abstract class NativeWindowFactory { static boolean initialized = false; - private static void initNativeImpl(final boolean firstUIActionOnProcess, final ClassLoader cl) { + private static void initSingletonNativeImpl(final boolean firstUIActionOnProcess, final ClassLoader cl) { isFirstUIActionOnProcess = firstUIActionOnProcess; - - String clazzName = null; + + final String clazzName; if( TYPE_X11.equals(nativeWindowingTypePure) ) { clazzName = X11UtilClassName; } else if( TYPE_WINDOWS.equals(nativeWindowingTypePure) ) { clazzName = GDIClassName; } else if( TYPE_MACOSX.equals(nativeWindowingTypePure) ) { clazzName = OSXUtilClassName; + } else { + clazzName = null; } if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "initSingleton", @@ -152,7 +164,7 @@ public abstract class NativeWindowFactory { requiresToolkitLock = res.booleanValue(); } else { requiresToolkitLock = false; - } + } } /** @@ -178,6 +190,8 @@ public abstract class NativeWindowFactory { System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.initSingleton("+firstUIActionOnProcess+")"); } + final ClassLoader cl = NativeWindowFactory.class.getClassLoader(); + // Gather the windowing OS first AccessControlContext acc = AccessController.getContext(); nativeWindowingTypePure = _getNativeWindowingType(); @@ -188,12 +202,10 @@ public abstract class NativeWindowFactory { nativeWindowingTypeCustom = tmp; } - final ClassLoader cl = NativeWindowFactory.class.getClassLoader(); - if(firstUIActionOnProcess) { // X11 initialization before possible AWT initialization - initNativeImpl(true, cl); - } + initSingletonNativeImpl(true, cl); + } isAWTAvailable = false; // may be set to true below if( !Debug.getBooleanProperty("java.awt.headless", true, acc) && @@ -203,7 +215,7 @@ public abstract class NativeWindowFactory { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { try { - jawtUtilClass = Class.forName(JAWTUtilClassName, false, NativeWindowFactory.class.getClassLoader()); + jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader()); jawtUtilInitMethod = jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null); jawtUtilInitMethod.setAccessible(true); jawtUtilGetJAWTToolkitMethod = jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); @@ -227,7 +239,7 @@ public abstract class NativeWindowFactory { } if(!firstUIActionOnProcess) { // X11 initialization after possible AWT initialization - initNativeImpl(false, cl); + initSingletonNativeImpl(false, cl); } registeredFactories = Collections.synchronizedMap(new HashMap<Class<?>, NativeWindowFactory>()); @@ -260,6 +272,21 @@ public abstract class NativeWindowFactory { } } + public static synchronized void shutdown() { + if(initialized) { + initialized = false; + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() START"); + } + registeredFactories.clear(); + registeredFactories = null; + // X11Util.shutdown(..) already called via GLDrawableFactory.shutdown() .. + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END"); + } + } + } + /** @return true if initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, otherwise false. */ public static boolean isFirstUIActionOnProcess() { @@ -319,31 +346,30 @@ public abstract class NativeWindowFactory { * <ul> * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> * <ul> - * <li>If native <b>X11 type</b> with or w/o AWT</li> - * <ul> - * <li> If <b>AWT available</b> </li> + * <li>If <b>AWT-type</b> and <b>native-X11-type</b> and <b>AWT-available</b></li> * <ul> * <li> return {@link jogamp.nativewindow.jawt.JAWTToolkitLock} </li> * </ul> - * </ul> * </ul> * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock getDefaultToolkitLock(String type) { if( requiresToolkitLock() ) { - if( TYPE_X11 == type || TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) ) { - if( isAWTAvailable() ) { - return getAWTToolkitLock(); - } + if( TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) && isAWTAvailable() ) { + return getAWTToolkitLock(); } } return NativeWindowFactoryImpl.getNullToolkitLock(); } - protected static ToolkitLock getAWTToolkitLock() { + private static ToolkitLock getAWTToolkitLock() { Object resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitMethod); + if(DEBUG) { + System.err.println("NativeWindowFactory.getAWTToolkitLock()"); + Thread.dumpStack(); + } if(resO instanceof ToolkitLock) { return (ToolkitLock) resO; } else { @@ -363,26 +389,49 @@ public abstract class NativeWindowFactory { * <ul> * <li>If <b>X11 type</b> </li> * <ul> - * <li> If <b>AWT available</b> </li> + * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> + * </ul> + * </ul> + * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> + * </ul> + */ + public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { + if( requiresToolkitLock() ) { + if( TYPE_X11 == type ) { + if( 0== deviceHandle ) { + throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); + } + return createX11ToolkitLock(deviceHandle); + } + } + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + /** + * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. + * <br> + * <ul> + * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> + * <ul> + * <li>If <b>X11 type</b> </li> + * <ul> + * <li> If <b>shared-AWT-type</b> and <b>AWT available</b> </li> * <ul> * <li> return {@link jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock} </li> * </ul> - * <li> If <b>AWT not available</b> </li> - * <ul> - * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> - * </ul> + * <li> else return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> * </ul> * </ul> * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ - public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { + public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) { if( requiresToolkitLock() ) { if( TYPE_X11 == type ) { if( 0== deviceHandle ) { throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); } - if( isAWTAvailable() ) { + if( TYPE_AWT == sharedType && isAWTAvailable() ) { return createX11AWTToolkitLock(deviceHandle); } return createX11ToolkitLock(deviceHandle); @@ -393,6 +442,10 @@ public abstract class NativeWindowFactory { protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) { try { + if(DEBUG) { + System.err.println("NativeWindowFactory.createX11AWTToolkitLock(0x"+Long.toHexString(deviceHandle)+")"); + Thread.dumpStack(); + } return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); } catch (Exception ex) { throw new RuntimeException(ex); @@ -470,4 +523,37 @@ public abstract class NativeWindowFactory { NativeWindow. Implementors of concrete NativeWindowFactory subclasses should override this method. */ protected abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException; + + /** + * Returns the {@link OffscreenLayerSurface} instance of this {@link NativeSurface}. + * <p> + * In case this surface is a {@link NativeWindow}, we traverse from the given surface + * up to root until an implementation of {@link OffscreenLayerSurface} is found. + * In case <code>ifEnabled</code> is true, the surface must also implement {@link OffscreenLayerOption} + * where {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()} is <code>true</code>. + * </p> + * + * @param surface The surface to query. + * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()}. + * @return + */ + public static OffscreenLayerSurface getOffscreenLayerSurface(NativeSurface surface, boolean ifEnabled) { + if(surface instanceof OffscreenLayerSurface && + ( !ifEnabled || surface instanceof OffscreenLayerOption ) ) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) surface; + return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + if(surface instanceof NativeWindow) { + NativeWindow nw = ((NativeWindow) surface).getParent(); + while(null != nw) { + if(nw instanceof OffscreenLayerSurface && + ( !ifEnabled || nw instanceof OffscreenLayerOption ) ) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) nw; + return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + nw = nw.getParent(); + } + } + return null; + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java new file mode 100644 index 000000000..12d30b3cd --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java @@ -0,0 +1,61 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.nativewindow; + +/** + * Handling requests for using an {@link OffscreenLayerSurface} + * within the implementation. + */ +public interface OffscreenLayerOption { + /** + * Request an offscreen layer, if supported. + * <p> + * Shall be called before the first {@link NativeWindow#lockSurface()}, + * and hence before realization. + * </p> + * + * @see #getShallUseOffscreenLayer() + * @see #isOffscreenLayerSurfaceEnabled() + */ + public void setShallUseOffscreenLayer(boolean v); + + /** Returns the property set by {@link #setShallUseOffscreenLayer(boolean)}. */ + public boolean getShallUseOffscreenLayer(); + + /** + * Returns true if this instance uses an offscreen layer, otherwise false. + * <p> + * This instance is an offscreen layer, if {@link #setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)} + * has been called before it's realization and first lock and the underlying implementation supports it. + * </p> + * The return value is undefined before issuing the first {@link NativeWindow#lockSurface()}. + * + * @see #setShallUseOffscreenLayer(boolean) + */ + public boolean isOffscreenLayerSurfaceEnabled(); +}
\ No newline at end of file diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java new file mode 100644 index 000000000..dd36509ba --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -0,0 +1,48 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.nativewindow; + +/** + * Interface specifying the offscreen layer surface protocol. + */ +public interface OffscreenLayerSurface { + /** + * Attach the offscreen layer to this offscreen layer surface. + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + */ + public void attachSurfaceLayer(final long layerHandle) throws NativeWindowException; + + /** + * Detaches a previously attached offscreen layer from this offscreen layer surface. + * @see #attachSurfaceLayer(long) + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + */ + public void detachSurfaceLayer(final long layerHandle) throws NativeWindowException; +} diff --git a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java index e34476228..9100beac2 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java @@ -28,12 +28,15 @@ package javax.media.nativewindow; +import jogamp.nativewindow.SurfaceUpdatedHelper; + import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; public abstract class ProxySurface implements NativeSurface { + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); + private AbstractGraphicsConfiguration config; // control access due to delegation protected RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); - protected AbstractGraphicsConfiguration config; protected long displayHandle; protected int height; protected int scrnIndex; @@ -42,7 +45,7 @@ public abstract class ProxySurface implements NativeSurface { public ProxySurface(AbstractGraphicsConfiguration cfg) { invalidate(); config = cfg; - displayHandle=cfg.getScreen().getDevice().getHandle(); + displayHandle=cfg.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); } void invalidate() { @@ -55,12 +58,16 @@ public abstract class ProxySurface implements NativeSurface { return displayHandle; } - public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { return config; } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); + } public final int getScreenIndex() { - return config.getScreen().getIndex(); + return getGraphicsConfiguration().getScreen().getIndex(); } public abstract long getSurfaceHandle(); @@ -73,7 +80,7 @@ public abstract class ProxySurface implements NativeSurface { return height; } - public void setSize(int width, int height) { + public void surfaceSizeChanged(int width, int height) { this.width = width; this.height = height; } @@ -82,16 +89,29 @@ public abstract class ProxySurface implements NativeSurface { return false; } - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } + public int lockSurface() throws NativeWindowException { surfaceLock.lock(); int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { try { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); adevice.lock(); try { res = lockSurfaceImpl(); @@ -113,7 +133,7 @@ public abstract class ProxySurface implements NativeSurface { surfaceLock.validateLocked(); if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); } finally { @@ -143,5 +163,5 @@ public abstract class ProxySurface implements NativeSurface { return surfaceLock.getOwner(); } - public abstract String toString(); + public abstract String toString(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java b/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java index fc32b57b3..956e68e61 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java @@ -41,8 +41,14 @@ package javax.media.nativewindow; public interface SurfaceChangeable { + /** Sets the surface handle which is created outside of this implementation */ public void setSurfaceHandle(long surfaceHandle); - public void setSize(int width, int height); + + /** + * The surface's size has been determined or changed. + * Implementation shall update the stored surface size with the given ones. + */ + public void surfaceSizeChanged(int width, int height); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java b/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java index 88e805d14..0912b5afe 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java +++ b/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java @@ -34,8 +34,12 @@ package javax.media.nativewindow; +/** + * Clients may add their SurfaceUpdateListener implementation to a {@link javax.media.nativewindow.NativeSurface} + * allowing to get notified after the surface has been updated, eg. after a swap buffer operation. + */ public interface SurfaceUpdatedListener { - /** Notification of a surface update event. + /** Notification of a surface update event, eg. after a swap buffer operation. * * @param updater is the caller object who updated the surface, * e.g. a JOGL GLDrawable. diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java index d83a92a5b..45a3db838 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java @@ -41,11 +41,13 @@ package javax.media.nativewindow.awt; import javax.media.nativewindow.*; + import java.awt.Component; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.image.ColorModel; import javax.media.nativewindow.AbstractGraphicsConfiguration; + import jogamp.nativewindow.Debug; /** A wrapper for an AWT GraphicsConfiguration allowing it to be @@ -63,56 +65,61 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple this.encapsulated=encapsulated; } - public AWTGraphicsConfiguration(AWTGraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - GraphicsConfiguration config) { + private AWTGraphicsConfiguration(AWTGraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + GraphicsConfiguration config) { super(screen, capsChosen, capsRequested); this.config = config; this.encapsulated=null; } - + /** * @param capsChosen if null, <code>capsRequested</code> is copied and aligned - * with the graphics capabilties of the AWT Component to produce the chosen Capabilties. + * with the graphics Capabilities of the AWT Component to produce the chosen Capabilities. * Otherwise the <code>capsChosen</code> is used. */ - public static AWTGraphicsConfiguration create(Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) - { - AWTGraphicsScreen awtScreen = null; - AWTGraphicsDevice awtDevice = null; - GraphicsDevice awtGraphicsDevice = null; - GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration(); - if(null!=awtGfxConfig) { - awtGraphicsDevice = awtGfxConfig.getDevice(); - if(null!=awtGraphicsDevice) { - // Create Device/Screen - awtDevice = new AWTGraphicsDevice(awtGraphicsDevice, AbstractGraphicsDevice.DEFAULT_UNIT); - awtScreen = new AWTGraphicsScreen(awtDevice); - } + public static AWTGraphicsConfiguration create(Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + final GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration(); + if(null==awtGfxConfig) { + throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp); } - if(null==awtScreen) { - // use defaults since no native peer is available yet - awtScreen = (AWTGraphicsScreen) AWTGraphicsScreen.createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); - awtDevice = (AWTGraphicsDevice) awtScreen.getDevice(); - awtGraphicsDevice = awtDevice.getGraphicsDevice(); + final GraphicsDevice awtGraphicsDevice = awtGfxConfig.getDevice(); + if(null==awtGraphicsDevice) { + throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsDevice @ "+awtGfxConfig); } + // Create Device/Screen + final AWTGraphicsDevice awtDevice = new AWTGraphicsDevice(awtGraphicsDevice, AbstractGraphicsDevice.DEFAULT_UNIT); + final AWTGraphicsScreen awtScreen = new AWTGraphicsScreen(awtDevice); + if(null==capsChosen) { GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); - capsChosen = setupCapabilitiesRGBABits(capsChosen, gc); + capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsRequested, gc); + } + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, null, awtScreen); + if(config instanceof AWTGraphicsConfiguration) { + return (AWTGraphicsConfiguration) config; } + // System.err.println("Info: AWTGraphicsConfiguration.create: Expected AWTGraphicsConfiguration got: "+config.getClass()+" w/ factory "+factory.getClass()+" - Unable to encapsulate native GraphicsConfiguration."); return new AWTGraphicsConfiguration(awtScreen, capsChosen, capsRequested, awtGfxConfig); } - @Override + // open access to superclass method + public void setChosenCapabilities(CapabilitiesImmutable capsChosen) { + super.setChosenCapabilities(capsChosen); + } + + @Override public Object clone() { return super.clone(); } - public GraphicsConfiguration getGraphicsConfiguration() { + /** Return the AWT {@link GraphicsConfiguration}. */ + public GraphicsConfiguration getAWTGraphicsConfiguration() { return config; } - @Override + @Override public AbstractGraphicsConfiguration getNativeGraphicsConfiguration() { return (null!=encapsulated)?encapsulated:this; } @@ -156,7 +163,7 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple return capabilities; } - @Override + @Override public String toString() { return getClass().getSimpleName()+"[" + getScreen() + ",\n\tchosen " + capabilitiesChosen+ diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java index 66a63bfcd..8ebe37626 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -46,26 +47,20 @@ import javax.media.nativewindow.AbstractGraphicsDevice; /** A wrapper for an AWT GraphicsDevice allowing it to be handled in a toolkit-independent manner. */ - public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { private GraphicsDevice device; - private String subType; - protected AWTGraphicsDevice(GraphicsDevice device, int unitID) { + public AWTGraphicsDevice(GraphicsDevice device, int unitID) { super(NativeWindowFactory.TYPE_AWT, device.getIDstring(), unitID); this.device = device; - this.subType = null; } - public static AbstractGraphicsDevice createDevice(GraphicsDevice awtDevice, int unitID) { - if(null==awtDevice) { - awtDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); - unitID = AbstractGraphicsDevice.DEFAULT_UNIT; - } - return new AWTGraphicsDevice(awtDevice, unitID); + public static AWTGraphicsDevice createDefault() { + GraphicsDevice awtDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + return new AWTGraphicsDevice(awtDevice, AbstractGraphicsDevice.DEFAULT_UNIT); } - @Override + @Override public Object clone() { return super.clone(); } @@ -74,26 +69,9 @@ public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl return device; } - /** - * In case the native handle was specified, e.g. using X11, - * we shall be able to mark it.<br> - * This will also set the subType, queried with {@link #getSubType()} - * and reset the ToolkitLock type with {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)} - * and {@link #setToolkitLock(javax.media.nativewindow.ToolkitLock)}. - */ - public void setSubType(String subType, long handle) { - this.handle = handle; - this.subType = subType; - setToolkitLock( NativeWindowFactory.createDefaultToolkitLock(subType, handle) ); - } - - public String getSubType() { - return subType; - } - - @Override + @Override public String toString() { - return getClass().getSimpleName()+"[type "+getType()+"[subType "+getSubType()+"], connection "+getConnection()+", unitID "+getUnitID()+", awtDevice "+device+", handle 0x"+Long.toHexString(getHandle())+"]"; + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", awtDevice "+device+", handle 0x"+Long.toHexString(getHandle())+"]"; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java index 383dcae80..2978d7868 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -42,7 +43,6 @@ package javax.media.nativewindow.awt; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import javax.media.nativewindow.*; -import javax.media.nativewindow.AbstractGraphicsDevice; /** A wrapper for an AWT GraphicsDevice (screen) allowing it to be handled in a toolkit-independent manner. */ @@ -74,17 +74,15 @@ public class AWTGraphicsScreen extends DefaultGraphicsScreen implements Cloneabl } public static AbstractGraphicsScreen createScreenDevice(GraphicsDevice awtDevice, int unitID) { - AWTGraphicsDevice device = (AWTGraphicsDevice) AWTGraphicsDevice.createDevice(awtDevice, unitID); - return new AWTGraphicsScreen(device); + return new AWTGraphicsScreen(new AWTGraphicsDevice(awtDevice, unitID)); } public static AbstractGraphicsScreen createScreenDevice(int index, int unitID) { - GraphicsDevice awtDevice = getScreenDevice(index); - return createScreenDevice(awtDevice, unitID); + return createScreenDevice(getScreenDevice(index), unitID); } public static AbstractGraphicsScreen createDefault() { - return createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); + return new AWTGraphicsScreen(AWTGraphicsDevice.createDefault()); } public Object clone() { diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java index 100b6b839..74439336d 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java @@ -1,5 +1,6 @@ /* * 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 @@ -32,8 +33,9 @@ package javax.media.nativewindow.x11; -import javax.media.nativewindow.*; +import javax.media.nativewindow.CapabilitiesImmutable; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.x11.XVisualInfo; /** Encapsulates a graphics configuration, or OpenGL pixel format, on @@ -42,7 +44,7 @@ import jogamp.nativewindow.x11.XVisualInfo; GraphicsConfigurationFactory.chooseGraphicsConfiguration()} on X11 platforms when toolkits other than the AWT are being used. */ -public class X11GraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class X11GraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { private XVisualInfo info; public X11GraphicsConfiguration(X11GraphicsScreen screen, diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java index 48fd63e3c..73c8cfd52 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java @@ -1,5 +1,6 @@ /* * 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 @@ -33,6 +34,7 @@ package javax.media.nativewindow.x11; import jogamp.nativewindow.Debug; +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import javax.media.nativewindow.DefaultGraphicsDevice; import javax.media.nativewindow.NativeWindowException; @@ -44,49 +46,49 @@ import javax.media.nativewindow.ToolkitLock; public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { public static final boolean DEBUG = Debug.debug("GraphicsDevice"); - boolean closeDisplay = false; + final boolean closeDisplay; /** Constructs a new X11GraphicsDevice corresponding to the given connection and default - * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)}.<br> + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#getDefaultToolkitLock(String)}.<br> * Note that this is not an open connection, ie no native display handle exist. * This constructor exist to setup a default device connection. + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int) */ public X11GraphicsDevice(String connection, int unitID) { super(NativeWindowFactory.TYPE_X11, connection, unitID); + closeDisplay = false; } /** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default - * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)}. + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long) */ - public X11GraphicsDevice(long display, int unitID) { + public X11GraphicsDevice(long display, int unitID, boolean owner) { // FIXME: derive unitID from connection could be buggy, one DISPLAY for all screens for example.. - super(NativeWindowFactory.TYPE_X11, X11Util.XDisplayString(display), unitID, display); + super(NativeWindowFactory.TYPE_X11, X11Lib.XDisplayString(display), unitID, display); if(0==display) { throw new NativeWindowException("null display"); } + closeDisplay = owner; } /** * @param display the Display connection * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking in NEWT + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long, ToolkitLock) */ - public X11GraphicsDevice(long display, int unitID, ToolkitLock locker) { - super(NativeWindowFactory.TYPE_X11, X11Util.XDisplayString(display), unitID, display, locker); + public X11GraphicsDevice(long display, int unitID, ToolkitLock locker, boolean owner) { + super(NativeWindowFactory.TYPE_X11, X11Lib.XDisplayString(display), unitID, display, locker); if(0==display) { throw new NativeWindowException("null display"); } + closeDisplay = owner; } public Object clone() { return super.clone(); } - public void setCloseDisplay(boolean close) { - closeDisplay = close; - if(DEBUG && close) { - System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.setCloseDisplay(true): "+this); - } - } public boolean close() { // FIXME: shall we respect the unitID ? if(closeDisplay && 0 != handle) { @@ -94,10 +96,8 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.close(): "+this); } X11Util.closeDisplay(handle); - handle = 0; - return true; } - return false; + return super.close(); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java index ffe84cb6d..6473b9f67 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java @@ -1,5 +1,6 @@ /* * 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 @@ -33,6 +34,8 @@ package javax.media.nativewindow.x11; import javax.media.nativewindow.*; + +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; /** Encapsulates a screen index on X11 @@ -48,22 +51,22 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl super(device, fetchScreen(device, screen)); } - public static AbstractGraphicsScreen createScreenDevice(long display, int screenIdx) { + public static AbstractGraphicsScreen createScreenDevice(long display, int screenIdx, boolean owner) { if(0==display) throw new NativeWindowException("display is null"); - return new X11GraphicsScreen(new X11GraphicsDevice(display, AbstractGraphicsDevice.DEFAULT_UNIT), screenIdx); + return new X11GraphicsScreen(new X11GraphicsDevice(display, AbstractGraphicsDevice.DEFAULT_UNIT, owner), screenIdx); } public long getDefaultVisualID() { // It still could be an AWT hold handle .. long display = getDevice().getHandle(); - int scrnIdx = X11Util.DefaultScreen(display); - return X11Util.DefaultVisualID(display, scrnIdx); + int scrnIdx = X11Lib.DefaultScreen(display); + return X11Lib.DefaultVisualID(display, scrnIdx); } private static int fetchScreen(X11GraphicsDevice device, int screen) { // It still could be an AWT hold handle .. long display = device.getHandle(); - if(X11Util.XineramaEnabled(display)) { + if(X11Lib.XineramaEnabled(display)) { screen = 0; // Xinerama -> 1 screen } return screen; diff --git a/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java b/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java new file mode 100644 index 000000000..ee3ab73ba --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java @@ -0,0 +1,43 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.DefaultGraphicsConfiguration; + +public class MutableGraphicsConfiguration extends DefaultGraphicsConfiguration { + public MutableGraphicsConfiguration(AbstractGraphicsScreen screen, + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + super(screen, capsChosen, capsRequested); + } + + public void setChosenCapabilities(CapabilitiesImmutable caps) { + super.setChosenCapabilities(caps); + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java index 2b6d3c016..4cf8f448e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java @@ -33,6 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.jvm.JNILibLoaderBase; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.cache.TempJarCache; public class NWJNILibLoader extends JNILibLoaderBase { @@ -40,9 +41,10 @@ public class NWJNILibLoader extends JNILibLoaderBase { public static void loadNativeWindow(final String ossuffix) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { + Platform.initSingleton(); final String libName = "nativewindow_"+ossuffix ; if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { - addNativeJarLibs(NWJNILibLoader.class, "jogl.all", "jogl-all", new String[] { "nativewindow" } ); + addNativeJarLibs(NWJNILibLoader.class, "jogl-all", new String[] { "nativewindow" } ); } loadLibrary(libName, false); return null; diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index d34d4e58f..223078ebf 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -32,11 +32,15 @@ package jogamp.nativewindow; -import com.jogamp.common.os.Platform; -import com.jogamp.common.util.*; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ToolkitLock; -import javax.media.nativewindow.*; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.ReflectionUtil; public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); @@ -44,13 +48,10 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { public static ToolkitLock getNullToolkitLock() { return nullToolkitLock; } - + // This subclass of NativeWindowFactory handles the case of // NativeWindows being passed in protected NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException { - if (null == winObj) { - throw new IllegalArgumentException("winObj is null"); - } if (winObj instanceof NativeWindow) { // Use the NativeWindow directly return (NativeWindow) winObj; @@ -69,7 +70,7 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { "javax.media.nativewindow.NativeWindow or "+AWTComponentClassName); } - private Constructor nativeWindowConstructor = null; + private Constructor<?> nativeWindowConstructor = null; private NativeWindow getAWTNativeWindow(Object winObj, AbstractGraphicsConfiguration config) { if (nativeWindowConstructor == null) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java new file mode 100644 index 000000000..4877d5c4f --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java @@ -0,0 +1,85 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.nativewindow; + +import java.util.ArrayList; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.SurfaceUpdatedListener; + +public class SurfaceUpdatedHelper implements SurfaceUpdatedListener { + private Object surfaceUpdatedListenersLock = new Object(); + private ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); + + // + // Management Utils + // + public int size() { return surfaceUpdatedListeners.size(); } + public SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); } + + // + // Implementation of NativeSurface SurfaceUpdatedListener methods + // + + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + addSurfaceUpdatedListener(-1, l); + } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size(); + } + surfaceUpdatedListeners.add(index, l); + } + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + if (l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners.remove(l); + } + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + synchronized(surfaceUpdatedListenersLock) { + for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { + SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); + l.surfaceUpdated(updater, ns, when); + } + } + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index 4c2b1c875..074fab563 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -33,7 +33,7 @@ import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.SurfaceChangeable; -public class WrappedSurface extends ProxySurface implements SurfaceChangeable { +public class WrappedSurface extends ProxySurface implements SurfaceChangeable { protected long surfaceHandle; public WrappedSurface(AbstractGraphicsConfiguration cfg) { @@ -65,6 +65,10 @@ public class WrappedSurface extends ProxySurface implements SurfaceChangeable { } public String toString() { - return "WrappedSurface[config " + config + ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + ", size " + getWidth() + "x" + getHeight() + "]"; + return "WrappedSurface[config " + getPrivateGraphicsConfiguration()+ + ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + + ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + + ", size " + getWidth() + "x" + getHeight() + + ", surfaceLock "+surfaceLock+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java index 2c8538278..354bb83e3 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java @@ -40,14 +40,15 @@ package jogamp.nativewindow.jawt; import javax.media.nativewindow.NativeWindowFactory; + import jogamp.nativewindow.NWJNILibLoader; import java.awt.Toolkit; import java.security.AccessController; import java.security.PrivilegedAction; -public class JAWTJNILibLoader extends NWJNILibLoader { - public static void loadAWTImpl() { +public class JAWTJNILibLoader extends NWJNILibLoader { + static { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { // Make sure that awt.dll is loaded before loading jawt.dll. Otherwise @@ -73,4 +74,9 @@ public class JAWTJNILibLoader extends NWJNILibLoader { } }); } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index c1c97eece..21e9a3e09 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -37,24 +37,28 @@ package jogamp.nativewindow.jawt; -import jogamp.nativewindow.*; import java.awt.EventQueue; - -import javax.media.nativewindow.*; - - import java.awt.GraphicsEnvironment; import java.awt.Toolkit; -import java.lang.reflect.*; -import java.security.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Map; +import javax.media.nativewindow.NativeWindowException; + +import jogamp.nativewindow.Debug; + +import com.jogamp.common.os.Platform; + public class JAWTUtil { protected static final boolean DEBUG = Debug.debug("JAWT"); // See whether we're running in headless mode private static final boolean headlessMode; + private static final JAWT jawtLockObject; // Java2D magic .. private static final Method isQueueFlusherThread; @@ -75,31 +79,67 @@ public class JAWTUtil { boolean ok; } + /** + * Returns true if this platform's JAWT implementation supports + * or uses offscreen layer. + */ + public static boolean isOffscreenLayerSupported() { + return Platform.OS_TYPE == Platform.OSType.MACOS && + Platform.OS_VERSION_NUMBER.compareTo(JAWT.JAWT_MacOSXCALayerMinVersion) >= 0; + } + + /** + * @param useOffscreenLayerIfAvailable + * @return + */ + public static JAWT getJAWT(boolean useOffscreenLayerIfAvailable) { + int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; + if(useOffscreenLayerIfAvailable) { + switch(Platform.OS_TYPE) { + case MACOS: + if(Platform.OS_VERSION_NUMBER.compareTo(JAWT.JAWT_MacOSXCALayerMinVersion) >= 0) { + jawt_version_flags |= JAWT.JAWT_MACOSX_USE_CALAYER; + } + } + } + return JAWT.getJAWT(jawt_version_flags); + } + + public static boolean isJAWTUsingOffscreenLayer(JAWT jawt) { + return 0 != ( jawt.getCachedVersion() & JAWT.JAWT_MACOSX_USE_CALAYER ); + } + static { - JAWTJNILibLoader.loadAWTImpl(); + if(DEBUG) { + System.err.println("JAWTUtil initialization (JAWT/JNI/..."); + // Thread.dumpStack(); + } + JAWTJNILibLoader.initSingleton(); JAWTJNILibLoader.loadNativeWindow("awt"); headlessMode = GraphicsEnvironment.isHeadless(); - boolean ok = false; - Class jC = null; + Class<?> jC = null; Method m = null; if (!headlessMode) { + jawtLockObject = getJAWT(false); // don't care for offscreen layer here try { jC = Class.forName("jogamp.opengl.awt.Java2D"); m = jC.getMethod("isQueueFlusherThread", (Class[])null); ok = true; } catch (Exception e) { } + } else { + jawtLockObject = null; // headless ! } isQueueFlusherThread = m; j2dExist = ok; - PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction() { + PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); try { - final Class sunToolkitClass = Class.forName("sun.awt.SunToolkit"); + final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); d.sunToolkitAWTLockMethod.setAccessible(true); d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); @@ -129,21 +169,21 @@ public class JAWTUtil { jawtToolkitLock = new JAWTToolkitLock(); // trigger native AWT toolkit / properties initialization - Map desktophints = null; + Map<?,?> desktophints = null; try { if(EventQueue.isDispatchThread()) { - desktophints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); } else { - final ArrayList desktophintsBucket = new ArrayList(1); + final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1); EventQueue.invokeAndWait(new Runnable() { public void run() { - Map _desktophints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if(null!=_desktophints) { desktophintsBucket.add(_desktophints); } } }); - desktophints = ( desktophintsBucket.size() > 0 ) ? (Map)desktophintsBucket.get(0) : null ; + desktophints = ( desktophintsBucket.size() > 0 ) ? desktophintsBucket.get(0) : null ; } } catch (InterruptedException ex) { ex.printStackTrace(); @@ -189,7 +229,7 @@ public class JAWTUtil { * JAWT's native Lock() function calls SunToolkit.awtLock(), * which just uses AWT's global ReentrantLock.<br> */ - public static void awtLock() { + private static void awtLock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTLockMethod.invoke(null, (Object[])null); @@ -197,7 +237,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtLock failed", e); } } else { - JAWT.getJAWT().Lock(); + jawtLockObject.Lock(); } } @@ -207,7 +247,7 @@ public class JAWTUtil { * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), * which just uses AWT's global ReentrantLock.<br> */ - public static void awtUnlock() { + private static void awtUnlock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); @@ -215,7 +255,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtUnlock failed", e); } } else { - JAWT.getJAWT().Unlock(); + jawtLockObject.Unlock(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java index 2c80392ad..be697b3e0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java @@ -41,73 +41,190 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; import java.awt.Component; -import java.awt.Window; +import java.awt.Container; +import java.applet.Applet; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; -public abstract class JAWTWindow implements NativeWindow { +import jogamp.nativewindow.SurfaceUpdatedHelper; + +public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption { protected static final boolean DEBUG = JAWTUtil.DEBUG; + // user properties + protected boolean shallUseOffscreenLayer = false; + // lifetime: forever protected Component component; - protected AbstractGraphicsConfiguration config; + private AWTGraphicsConfiguration config; // control access due to delegation + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - // lifetime: valid after lock, forever until invalidate + // lifetime: valid after lock but may change with each 1st lock, purges after invalidate + private boolean isApplet; + private JAWT jawt; + private boolean isOffscreenLayerSurface; protected long drawable; protected Rectangle bounds; - - public JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + protected Insets insets; + + /** + * Constructed by {@link jogamp.nativewindow.NativeWindowFactoryImpl#getNativeWindow(Object, AbstractGraphicsConfiguration)} + * via this platform's specialization (X11, OSX, Windows, ..). + * + * @param comp + * @param config + */ + protected JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { if (config == null) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is null"); } - this.config = config; + if(! ( config instanceof AWTGraphicsConfiguration ) ) { + throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config); + } + this.config = (AWTGraphicsConfiguration) config; init((Component)comp); } private void init(Component windowObject) throws NativeWindowException { invalidate(); this.component = windowObject; - validateNative(); + this.isApplet = false; } - protected abstract void validateNative() throws NativeWindowException; - + + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + public final boolean isOffscreenLayerSurfaceEnabled() { + return isOffscreenLayerSurface; + } + protected synchronized void invalidate() { - component = null; + invalidateNative(); + jawt = null; + isOffscreenLayerSurface = false; drawable= 0; bounds = new Rectangle(); + insets = new Insets(); } + protected abstract void invalidateNative(); protected final void updateBounds(JAWT_Rectangle jawtBounds) { bounds.setX(jawtBounds.getX()); bounds.setY(jawtBounds.getY()); bounds.setWidth(jawtBounds.getWidth()); bounds.setHeight(jawtBounds.getHeight()); + + if(component instanceof Container) { + java.awt.Insets contInsets = ((Container)component).getInsets(); + insets.setLeftWidth(contInsets.left); + insets.setRightWidth(contInsets.right); + insets.setTopHeight(contInsets.top); + insets.setBottomHeight(contInsets.bottom); + } } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } - public final InsetsImmutable getInsets() { return Insets.getZero(); } + public final InsetsImmutable getInsets() { return insets; } public final Component getAWTComponent() { return component; } + + /** + * Returns true if the AWT component is parented to an {@link java.applet.Applet}, + * otherwise false. This information is valid only after {@link #lockSurface()}. + */ + public final boolean isApplet() { + return isApplet; + } + /** Returns the underlying JAWT instance created @ {@link #lockSurface()}. */ + public final JAWT getJAWT() { + return jawt; + } + + /** + * {@inheritDoc} + */ + public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new NativeWindowException("Not an offscreen layer surface"); + } + int lockRes = lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock (offscreen layer): "+this); + } + try { + if(DEBUG) { + System.err.println("JAWTWindow.attachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); + } + attachSurfaceLayerImpl(layerHandle); + } finally { + unlockSurface(); + } + } + protected abstract void attachSurfaceLayerImpl(final long layerHandle); + + /** + * {@inheritDoc} + */ + public final void detachSurfaceLayer(final long layerHandle) throws NativeWindowException { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new java.lang.UnsupportedOperationException("Not an offscreen layer surface"); + } + int lockRes = lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock (offscreen layer): "+this); + } + try { + if(DEBUG) { + System.err.println("JAWTWindow.detachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); + } + detachSurfaceLayerImpl(layerHandle); + } finally { + unlockSurface(); + } + } + protected abstract void detachSurfaceLayerImpl(final long layerHandle); + // // SurfaceUpdateListener // - public final void surfaceUpdated(Object updater, NativeSurface ns, long when) { - // nop + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } // // NativeSurface @@ -115,6 +232,24 @@ public abstract class JAWTWindow implements NativeWindow { private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private void determineIfApplet() { + Component c = component; + while(!isApplet && null != c) { + isApplet = c instanceof Applet; + c = c.getParent(); + } + } + + /** + * If JAWT offscreen layer is supported, + * implementation shall respect {@link #getShallUseOffscreenLayer()} + * and may respect {@link #isApplet()}. + * + * @return The JAWT instance reflecting offscreen layer support, etc. + * + * @throws NativeWindowException + */ + protected abstract JAWT fetchJAWTImpl() throws NativeWindowException; protected abstract int lockSurfaceImpl() throws NativeWindowException; public final int lockSurface() throws NativeWindowException { @@ -122,10 +257,13 @@ public abstract class JAWTWindow implements NativeWindow { int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { + determineIfApplet(); try { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); adevice.lock(); try { + jawt = fetchJAWTImpl(); + isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); res = lockSurfaceImpl(); } finally { if (LOCK_SURFACE_NOT_READY >= res) { @@ -147,7 +285,7 @@ public abstract class JAWTWindow implements NativeWindow { surfaceLock.validateLocked(); if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); } finally { @@ -169,36 +307,35 @@ public abstract class JAWTWindow implements NativeWindow { return surfaceLock.getOwner(); } - public final boolean surfaceSwap() { + public boolean surfaceSwap() { return false; } - public final void surfaceUpdated(Object updater, NativeWindow window, long when) { } - - public final long getSurfaceHandle() { + public long getSurfaceHandle() { return drawable; } - public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + + public final AWTGraphicsConfiguration getPrivateGraphicsConfiguration() { return config; } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); + } public final long getDisplayHandle() { - return config.getScreen().getDevice().getHandle(); + return getGraphicsConfiguration().getScreen().getDevice().getHandle(); } public final int getScreenIndex() { - return config.getScreen().getIndex(); - } - - public final void setSize(int width, int height) { - component.setSize(width, height); + return getGraphicsConfiguration().getScreen().getIndex(); } - public final int getWidth() { + public int getWidth() { return component.getWidth(); } - public final int getHeight() { + public int getHeight() { return component.getHeight(); } @@ -207,12 +344,8 @@ public abstract class JAWTWindow implements NativeWindow { // public synchronized void destroy() { - if(null!=component) { - if(component instanceof Window) { - ((Window)component).dispose(); - } - } - invalidate(); + invalidate(); + component = null; // don't dispose the AWT component, since we are merely an immutable uplink } public final NativeWindow getParent() { @@ -222,7 +355,7 @@ public abstract class JAWTWindow implements NativeWindow { public long getWindowHandle() { return drawable; } - + public final int getX() { return component.getX(); } @@ -230,52 +363,94 @@ public abstract class JAWTWindow implements NativeWindow { public final int getY() { return component.getY(); } - + + /** + * {@inheritDoc} + * + * <p> + * This JAWT default implementation is currently still using + * a blocking implementation. It first attempts to retrieve the location + * via a native implementation. If this fails, it tries the blocking AWT implementation. + * If the latter fails due to an external AWT tree-lock, the non block + * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used. + * The latter simply traverse up to the AWT component tree and sums the rel. position. + * We have to determine whether the latter is good enough for all cases, + * currently only OS X utilizes the non blocking method per default. + * </p> + */ public Point getLocationOnScreen(Point storage) { + Point los = getLocationOnScreenNative(storage); + if(null == los) { + if(!Thread.holdsLock(component.getTreeLock())) { + // avoid deadlock .. + if(DEBUG) { + System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this); + Thread.dumpStack(); + } + return getLocationOnScreenNonBlocking(storage, component); + } + java.awt.Point awtLOS = component.getLocationOnScreen(); + if(null!=storage) { + los = storage.translate(awtLOS.x, awtLOS.y); + } else { + los = new Point(awtLOS.x, awtLOS.y); + } + } + return los; + } + + protected Point getLocationOnScreenNative(Point storage) { int lockRes = lockSurface(); if(LOCK_SURFACE_NOT_READY == lockRes) { - // FIXME: Shall we deal with already locked or unrealized surfaces ? - System.err.println("Warning: JAWT Lock couldn't be acquired!"); - Thread.dumpStack(); + if(DEBUG) { + System.err.println("Warning: JAWT Lock couldn't be acquired: "+this); + Thread.dumpStack(); + } return null; } try { - Point d = getLocationOnScreenImpl(0, 0); + Point d = getLocationOnScreenNativeImpl(0, 0); if(null!=d) { if(null!=storage) { storage.translate(d.getX(),d.getY()); return storage; } - return d; - } - // fall through intended .. - if(!Thread.holdsLock(component.getTreeLock())) { - // FIXME: Verify if this check is still required! - System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock!"); - Thread.dumpStack(); - return null; // avoid deadlock .. } - java.awt.Point awtLOS = component.getLocationOnScreen(); - int dx = (int) ( awtLOS.getX() + .5 ) ; - int dy = (int) ( awtLOS.getY() + .5 ) ; - if(null!=storage) { - return storage.translate(dx, dy); - } - return new Point(dx, dy); + return d; } finally { unlockSurface(); + } + } + protected abstract Point getLocationOnScreenNativeImpl(int x, int y); + + protected static Point getLocationOnScreenNonBlocking(Point storage, Component comp) { + int x = 0; + int y = 0; + while(null != comp) { + x += comp.getX(); + y += comp.getY(); + comp = comp.getParent(); } + if(null!=storage) { + storage.translate(x, y); + return storage; + } + return new Point(x, y); } - protected abstract Point getLocationOnScreenImpl(int x, int y); - - @Override + + public boolean hasFocus() { + return component.hasFocus(); + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("JAWT-Window["+ "windowHandle 0x"+Long.toHexString(getWindowHandle())+ ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", bounds "+bounds); + ", bounds "+bounds+", insets "+insets+ + ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface); if(null!=component) { sb.append(", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ ", visible "+component.isVisible()); @@ -283,8 +458,9 @@ public abstract class JAWTWindow implements NativeWindow { sb.append(", component NULL"); } sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ - ",\n\tconfig "+config+ - ",\n\tawtComponent "+getAWTComponent()+"]"); + ",\n\tconfig "+getPrivateGraphicsConfiguration()+ + ",\n\tawtComponent "+getAWTComponent()+ + ",\n\tsurfaceLock "+surfaceLock+"]"); return sb.toString(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index d4f6a95d4..ab2986fbe 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -40,38 +40,94 @@ package jogamp.nativewindow.jawt.macosx; -import java.awt.Component; +import java.nio.Buffer; import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.Capabilities; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.SurfaceChangeable; import javax.media.nativewindow.util.Point; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -// import jogamp.nativewindow.macosx.OSXUtil; - -public class MacOSXJAWTWindow extends JAWTWindow { +import jogamp.nativewindow.macosx.OSXUtil; +public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable { public MacOSXJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { super(comp, config); + if(DEBUG) { + dumpInfo(); + } } - protected void validateNative() throws NativeWindowException { + protected void invalidateNative() { + surfaceHandle=0; + if(isOffscreenLayerSurfaceEnabled()) { + if(0 != drawable) { + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + } + } } + protected void attachSurfaceLayerImpl(final long layerHandle) { + OSXUtil.AddCASublayer(rootSurfaceLayerHandle, layerHandle); + } + + protected void detachSurfaceLayerImpl(final long layerHandle) { + OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle); + } + + public long getSurfaceHandle() { + return isOffscreenLayerSurfaceEnabled() ? surfaceHandle : super.getSurfaceHandle() ; + } + + public void setSurfaceHandle(long surfaceHandle) { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new java.lang.UnsupportedOperationException("Not using CALAYER"); + } + if(DEBUG) { + System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + } + sscSet &= 0 != surfaceHandle; // reset ssc flag if NULL surfaceHandle, ie. back to JAWT + this.surfaceHandle = surfaceHandle; + } + + public void surfaceSizeChanged(int width, int height) { + sscSet = true; + sscWidth = width; + sscHeight = height; + } + + public int getWidth() { + return sscSet ? sscWidth : super.getWidth(); + } + + public int getHeight() { + return sscSet ? sscHeight: super.getHeight(); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + // use offscreen if supported and [ applet or requested ] + return JAWTUtil.getJAWT(getShallUseOffscreenLayer() || isApplet()); + } protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + int ret = NativeWindow.LOCK_SURFACE_NOT_READY; + if(null == ds) { + ds = getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } } int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; @@ -87,37 +143,86 @@ public class MacOSXJAWTWindow extends JAWTWindow { if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { ret = NativeWindow.LOCK_SURFACE_CHANGED; } - if (firstLock) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - dsi = ds.GetDrawingSurfaceInfo(); - return null; - } - }); - } else { - dsi = ds.GetDrawingSurfaceInfo(); + if(null == dsi) { + if (firstLock) { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + dsi = ds.GetDrawingSurfaceInfo(); + return null; + } + }); + } else { + dsi = ds.GetDrawingSurfaceInfo(); + } + if (dsi == null) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } } - if (dsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + updateBounds(dsi.getBounds()); + if (DEBUG && firstLock ) { + dumpInfo(); } firstLock = false; - macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(); - if (macosxdsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } - drawable = macosxdsi.getCocoaViewRef(); - - if (drawable == 0) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + if( !isOffscreenLayerSurfaceEnabled() ) { + macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(getJAWT()); + if (macosxdsi == null) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } + drawable = macosxdsi.getCocoaViewRef(); + + if (drawable == 0) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } else { + ret = NativeWindow.LOCK_SUCCESS; + } } else { - updateBounds(dsi.getBounds()); + /** + * Only create a fake invisible NSWindow for the drawable handle + * to please frameworks requiring such (eg. NEWT). + * + * The actual surface/ca-layer shall be created/attached + * by the upper framework (JOGL) since they require more information. + */ + if(0 == drawable) { + drawable = OSXUtil.CreateNSWindow(0, 0, getBounds().getWidth(), getBounds().getHeight()); + if(0 == drawable) { + unlockSurfaceImpl(); + throw new NativeWindowException("Unable to created dummy NSWindow (layered case)"); + } + // fix caps reflecting offscreen! + Capabilities caps = (Capabilities) getPrivateGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + getPrivateGraphicsConfiguration().setChosenCapabilities(caps); + caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); + } + if(0 == rootSurfaceLayerHandle) { + rootSurfaceLayerHandle = OSXUtil.CreateCALayer(); + if(0 == rootSurfaceLayerHandle) { + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException("Could not create root CALayer: "+this); + } + if(!AttachJAWTSurfaceLayer(dsi, rootSurfaceLayerHandle)) { + OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); + rootSurfaceLayerHandle = 0; + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException("Could not attach JAWT surfaceLayerHandle: "+this); + } + } + ret = NativeWindow.LOCK_SUCCESS; } + return ret; } - + protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -126,30 +231,65 @@ public class MacOSXJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; - macosxdsi = null; } - protected Point getLocationOnScreenImpl(int x, int y) { - Component c = component; - while(null != c) { - x += c.getX(); - y += c.getY(); - c = c.getParent(); + private void dumpInfo() { + System.err.println("MaxOSXJAWTWindow: 0x"+Integer.toHexString(this.hashCode())+" - thread: "+Thread.currentThread().getName()); + if(null != getJAWT()) { + System.err.println("JAWT version: 0x"+Integer.toHexString(getJAWT().getCachedVersion())+ + ", CA_LAYER: "+ JAWTUtil.isJAWTUsingOffscreenLayer(getJAWT())+ + ", isLayeredSurface "+isOffscreenLayerSurfaceEnabled()+", bounds "+bounds+", insets "+insets); + } else { + System.err.println("JAWT n/a, bounds "+bounds+", insets "+insets); } - // return OSXUtil.GetLocationOnScreen(getWindowHandle(), x, y); - return new Point(x, y); + // Thread.dumpStack(); } + + /** + * {@inheritDoc} + * <p> + * On OS X locking the surface at this point (ie after creation and for location validation) + * is 'tricky' since the JVM traverses through many threads and crashes at: + * lockSurfaceImpl() { + * .. + * ds = getJAWT().GetDrawingSurface(component); + * due to a SIGSEGV. + * + * Hence we have some threading / sync issues with the native JAWT implementation. + * </p> + */ + @Override + public Point getLocationOnScreen(Point storage) { + return getLocationOnScreenNonBlocking(storage, component); + } + protected Point getLocationOnScreenNativeImpl(final int x0, final int y0) { return null; } + private static boolean AttachJAWTSurfaceLayer(JAWT_DrawingSurfaceInfo dsi, long caLayer) { + if(0==caLayer) { + throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); + } + return AttachJAWTSurfaceLayer0(dsi.getBuffer(), caLayer); + } + + private static native boolean AttachJAWTSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; + private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; - + + private long rootSurfaceLayerHandle = 0; // is autoreleased, once it is attached to the JAWT_SurfaceLayer + + private long surfaceHandle = 0; + private int sscWidth, sscHeight; + private boolean sscSet = false; + // Workaround for instance of 4796548 private boolean firstLock = true; diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java index 5ad22807f..bf5c18eaf 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java @@ -95,7 +95,7 @@ public class Win32SunJDKReflection { public static int graphicsConfigurationGetPixelFormatID(AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { - return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getGraphicsConfiguration()); + return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; } catch (Exception e) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 982b94888..786682b17 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -47,10 +47,11 @@ import javax.media.nativewindow.util.Point; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; public class WindowsJAWTWindow extends JAWTWindow { @@ -58,18 +59,24 @@ public class WindowsJAWTWindow extends JAWTWindow { super(comp, config); } - protected void validateNative() throws NativeWindowException { - } - - @Override - protected synchronized void invalidate() { - super.invalidate(); + protected void invalidateNative() { windowHandle = 0; } + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + protected void detachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + return JAWTUtil.getJAWT(false); // no offscreen + } + protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); + ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); @@ -94,7 +101,8 @@ public class WindowsJAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(); + updateBounds(dsi.getBounds()); + win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (win32dsi == null) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; @@ -104,14 +112,12 @@ public class WindowsJAWTWindow extends JAWTWindow { if (windowHandle == 0 || drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } protected void unlockSurfaceImpl() throws NativeWindowException { - long startTime = 0; + drawable = 0; // invalid HDC if(null!=ds) { if (null!=dsi) { ds.FreeDrawingSurfaceInfo(dsi); @@ -119,7 +125,7 @@ public class WindowsJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; @@ -131,8 +137,8 @@ public class WindowsJAWTWindow extends JAWTWindow { return windowHandle; } - protected Point getLocationOnScreenImpl(int x, int y) { - return GDI.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); + protected Point getLocationOnScreenNativeImpl(int x, int y) { + return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java index 5d4fa0dad..743d371b7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java @@ -28,9 +28,13 @@ package jogamp.nativewindow.jawt.x11; import jogamp.nativewindow.jawt.*; +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import javax.media.nativewindow.ToolkitLock; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + /** * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. @@ -41,20 +45,32 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11JAWTToolkitLock implements ToolkitLock { long displayHandle; + RecursiveLock lock; public X11JAWTToolkitLock(long displayHandle) { this.displayHandle = displayHandle; + if(!X11Util.isNativeLockAvailable()) { + lock = LockFactory.createRecursiveLock(); + } } public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock()"); } + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } JAWTUtil.lockToolkit(); - X11Util.XLockDisplay(displayHandle); + if(null == lock) { + X11Lib.XLockDisplay(displayHandle); + } else { + lock.lock(); + } } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock()"); } - X11Util.XUnlockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XUnlockDisplay(displayHandle); + } else { + lock.unlock(); + } JAWTUtil.unlockToolkit(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 2319d6269..35dc2343f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -38,20 +38,17 @@ package jogamp.nativewindow.jawt.x11; import javax.media.nativewindow.AbstractGraphicsConfiguration; -import javax.media.nativewindow.AbstractGraphicsDevice; -import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; -import javax.media.nativewindow.awt.AWTGraphicsDevice; import javax.media.nativewindow.util.Point; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -import jogamp.nativewindow.x11.X11Util; +import jogamp.nativewindow.x11.X11Lib; public class X11JAWTWindow extends JAWTWindow { @@ -59,36 +56,22 @@ public class X11JAWTWindow extends JAWTWindow { super(comp, config); } - protected void validateNative() throws NativeWindowException { - AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); + protected void invalidateNative() { } - if(awtDevice.getHandle() != 0) { - // subtype and handle set already, done - return; - } - - long displayHandle = 0; - - // first try a pre-existing attached native configuration, ie native X11GraphicsDevice - AbstractGraphicsConfiguration aconfig = (null!=config) ? config.getNativeGraphicsConfiguration() : null; - AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; - AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; // X11GraphicsDevice - if(null!=adevice) { - displayHandle = adevice.getHandle(); - } - - if(0 == displayHandle) { - displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(awtDevice.getGraphicsDevice()); - } - if(0==displayHandle) { - throw new InternalError("X11JAWTWindow: No X11 Display handle available"); - } - awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); } - + protected void detachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + return JAWTUtil.getJAWT(false); // no offscreen + } + protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); + ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); @@ -113,7 +96,8 @@ public class X11JAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); + updateBounds(dsi.getBounds()); + x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (x11dsi == null) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; @@ -122,8 +106,6 @@ public class X11JAWTWindow extends JAWTWindow { if (drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } @@ -136,15 +118,15 @@ public class X11JAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; x11dsi = null; } - protected Point getLocationOnScreenImpl(int x, int y) { - return X11Util.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + protected Point getLocationOnScreenNativeImpl(int x, int y) { + return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java index b576b0c6b..08d471448 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java @@ -55,14 +55,14 @@ import javax.media.nativewindow.awt.AWTGraphicsConfiguration; the purposes of correctly enumerating the available visuals. */ public class X11SunJDKReflection { - private static Class x11GraphicsDeviceClass; - private static Method x11GraphicsDeviceGetDisplayMethod; - private static Class x11GraphicsConfigClass; - private static Method x11GraphicsConfigGetVisualMethod; - private static boolean initted; + private static Class<?> x11GraphicsDeviceClass; + private static Method x11GraphicsDeviceGetDisplayMethod; + private static Class<?> x11GraphicsConfigClass; + private static Method x11GraphicsConfigGetVisualMethod; + private static boolean initialized; static { - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { try { x11GraphicsDeviceClass = Class.forName("sun.awt.X11GraphicsDevice"); @@ -72,7 +72,7 @@ public class X11SunJDKReflection { x11GraphicsConfigClass = Class.forName("sun.awt.X11GraphicsConfig"); x11GraphicsConfigGetVisualMethod = x11GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); x11GraphicsConfigGetVisualMethod.setAccessible(true); - initted = true; + initialized = true; } catch (Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } @@ -82,7 +82,7 @@ public class X11SunJDKReflection { } public static long graphicsDeviceGetDisplay(GraphicsDevice device) { - if (!initted) { + if (!initialized) { return 0; } @@ -96,7 +96,7 @@ public class X11SunJDKReflection { public static int graphicsConfigurationGetVisualID(AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { - return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getGraphicsConfiguration()); + return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; } catch (Exception e) { @@ -105,7 +105,7 @@ public class X11SunJDKReflection { } public static int graphicsConfigurationGetVisualID(GraphicsConfiguration config) { - if (!initted) { + if (!initialized) { return 0; } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index cd558c05d..5b1e4b0a7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ package jogamp.nativewindow.macosx; import javax.media.nativewindow.NativeWindowException; @@ -34,6 +61,42 @@ public class OSXUtil { return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); } + public static long CreateNSView(int x, int y, int width, int height) { + return CreateNSView0(x, y, width, height); + } + public static void DestroyNSView(long nsView) { + DestroyNSView0(nsView); + } + + public static long CreateNSWindow(int x, int y, int width, int height) { + return CreateNSWindow0(x, y, width, height); + } + public static void DestroyNSWindow(long nsWindow) { + DestroyNSWindow0(nsWindow); + } + + public static long CreateCALayer() { + return CreateCALayer0(); + } + public static void AddCASublayer(long rootCALayer, long subCALayer) { + if(0==rootCALayer || 0==subCALayer) { + throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); + } + AddCASublayer0(rootCALayer, subCALayer); + } + public static void RemoveCASublayer(long rootCALayer, long subCALayer) { + if(0==rootCALayer || 0==subCALayer) { + throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); + } + RemoveCASublayer0(rootCALayer, subCALayer); + } + public static void DestroyCALayer(long caLayer) { + if(0==caLayer) { + throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); + } + DestroyCALayer0(caLayer); + } + public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) { if(IsMainThread0()) { runnable.run(); // don't leave the JVM @@ -48,6 +111,14 @@ public class OSXUtil { private static native boolean initIDs0(); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); + private static native long CreateNSView0(int x, int y, int width, int height); + private static native void DestroyNSView0(long nsView); + private static native long CreateNSWindow0(int x, int y, int width, int height); + private static native void DestroyNSWindow0(long nsWindow); + private static native long CreateCALayer0(); + private static native void AddCASublayer0(long rootCALayer, long subCALayer); + private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); + private static native void DestroyCALayer0(long caLayer); private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable); private static native boolean IsMainThread0(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java index 1ad909897..aab1556da 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java @@ -202,7 +202,9 @@ public class SWTAccessor { if( null != OS_gtk_class ) { long widgedHandle = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); long displayHandle = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, widgedHandle); - return new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT); + // FIXME: May think about creating a private non-shared X11 Display handle, like we use to for AWT + // to avoid locking problems ! + return new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, false); } if( NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false) ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java index 68cf8af45..c8ed8e070 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java @@ -61,14 +61,22 @@ public class GDISurface extends ProxySurface { throw new InternalError("surface not released"); } surfaceHandle = GDI.GetDC(windowHandle); + /* + if(0 == surfaceHandle) { + System.err.println("****** DC Acquire: 0x"+Long.toHexString(windowHandle)+", isWindow "+GDI.IsWindow(windowHandle)+", isVisible "+GDI.IsWindowVisible(windowHandle)+", GDI LastError: "+GDI.GetLastError()+", 0x"+Long.toHexString(surfaceHandle)+", GDI LastError: "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); + Thread.dumpStack(); + } + */ return (0 != surfaceHandle) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; } protected void unlockSurfaceImpl() { if (0 == surfaceHandle) { - throw new InternalError("surface not acquired"); + throw new InternalError("surface not acquired: "+this+", thread: "+Thread.currentThread().getName()); + } + if(0 == GDI.ReleaseDC(windowHandle, surfaceHandle)) { + throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); } - GDI.ReleaseDC(windowHandle, surfaceHandle); surfaceHandle=0; } @@ -77,11 +85,12 @@ public class GDISurface extends ProxySurface { } public String toString() { - return "GDISurface[config "+config+ + return "GDISurface[config "+getPrivateGraphicsConfiguration()+ ", displayHandle 0x"+Long.toHexString(getDisplayHandle())+ ", windowHandle 0x"+Long.toHexString(windowHandle)+ ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", size "+getWidth()+"x"+getHeight()+"]"; + ", size "+getWidth()+"x"+getHeight()+ + ", surfaceLock "+surfaceLock+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java new file mode 100644 index 000000000..be531d9ee --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -0,0 +1,101 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow.windows; + +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.NativeWindowException; + +import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.x11.X11Util; + +public class GDIUtil { + private static final boolean DEBUG = Debug.debug("GDIUtil"); + + private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ; + private static RegisteredClassFactory dummyWindowClassFactory; + private static boolean isInit = false; + + public static synchronized void initSingleton(boolean firstX11ActionOnProcess) { + if(!isInit) { + synchronized(X11Util.class) { + if(!isInit) { + isInit = true; + NWJNILibLoader.loadNativeWindow("win32"); + + if( !initIDs0() ) { + throw new NativeWindowException("GDI: Could not initialized native stub"); + } + + if(DEBUG) { + System.out.println("GDI.isFirstX11ActionOnProcess: "+firstX11ActionOnProcess); + } + + dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0()); + } + } + } + } + + public static boolean requiresToolkitLock() { return false; } + + private static RegisteredClass dummyWindowClass = null; + private static Object dummyWindowSync = new Object(); + + public static long CreateDummyWindow(int x, int y, int width, int height) { + synchronized(dummyWindowSync) { + dummyWindowClass = dummyWindowClassFactory.getSharedClass(); + return CreateDummyWindow0(dummyWindowClass.getHandle(), dummyWindowClass.getName(), dummyWindowClass.getName(), x, y, width, height); + } + } + + public static boolean DestroyDummyWindow(long hwnd) { + boolean res; + synchronized(dummyWindowSync) { + if( null == dummyWindowClass ) { + throw new InternalError("GDI Error ("+dummyWindowClassFactory.getSharedRefCount()+"): SharedClass is null"); + } + res = GDI.DestroyWindow(hwnd); + dummyWindowClassFactory.releaseSharedClass(); + } + return res; + } + + public static Point GetRelativeLocation(long src_win, long dest_win, int src_x, int src_y) { + return (Point) GetRelativeLocation0(src_win, dest_win, src_x, src_y); + } + + public static native boolean CreateWindowClass(long hInstance, String clazzName, long wndProc); + public static native boolean DestroyWindowClass(long hInstance, String className); + + private static native boolean initIDs0(); + private static native long getDummyWndProc0(); + private static native Object GetRelativeLocation0(long src_win, long dest_win, int src_x, int src_y); + + static native long CreateDummyWindow0(long hInstance, String className, String windowName, int x, int y, int width, int height); +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java index 15e0a67cb..00bedfc8e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java @@ -34,34 +34,44 @@ import javax.media.nativewindow.NativeWindowException; public class RegisteredClassFactory { static final boolean DEBUG = Debug.debug("RegisteredClass"); - private static ArrayList sharedClasses = new ArrayList(); + private static ArrayList<RegisteredClassFactory> registeredFactories = new ArrayList<RegisteredClassFactory>(); + private String classBaseName; - long wndProc; + private long wndProc; private RegisteredClass sharedClass = null; private int classIter = 0; private int sharedRefCount = 0; - private Object sync = new Object(); + private final Object sync = new Object(); /** - * Intended for a JVM shutdown hook, hence little synchronization + * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. */ public static void shutdownSharedClasses() { - synchronized(sharedClasses) { - for(int i=0; i<sharedClasses.size(); i++) { - RegisteredClass sc = (RegisteredClass) sharedClasses.get(i); - GDI.DestroyWindowClass(sc.getHandle(), sc.getName()); - if(DEBUG) { - System.err.println("RegisteredClassFactory shutdownSharedClasses "+i+"/"+sharedClasses.size()+": "+sc); + synchronized(registeredFactories) { + for(int j=0; j<registeredFactories.size(); j++) { + final RegisteredClassFactory rcf = registeredFactories.get(j); + synchronized(rcf.sync) { + if(null != rcf.sharedClass) { + GDIUtil.DestroyWindowClass(rcf.sharedClass.getHandle(), rcf.sharedClass.getName()); + rcf.sharedClass = null; + rcf.sharedRefCount = 0; + rcf.classIter = 0; + if(DEBUG) { + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+" shutdownSharedClasses : "+rcf.sharedClass); + } + } } } - sharedClasses.clear(); } } public RegisteredClassFactory(String classBaseName, long wndProc) { this.classBaseName = classBaseName; this.wndProc = wndProc; + synchronized(registeredFactories) { + registeredFactories.add(this); + } } public RegisteredClass getSharedClass() throws NativeWindowException { @@ -76,19 +86,17 @@ public class RegisteredClassFactory { } String clazzName = null; boolean registered = false; - while ( !registered && Integer.MAX_VALUE >= classIter ) { + final int classIterMark = classIter - 1; + while ( !registered && classIterMark != classIter ) { // Retry with next clazz name, this could happen if more than one JVM is running clazzName = classBaseName + classIter; classIter++; - registered = GDI.CreateWindowClass(hInstance, clazzName, wndProc); + registered = GDIUtil.CreateWindowClass(hInstance, clazzName, wndProc); } if( !registered ) { throw new NativeWindowException("Error: Could not create WindowClass: "+clazzName); } sharedClass = new RegisteredClass(hInstance, clazzName); - synchronized(sharedClasses) { - sharedClasses.add(sharedClass); - } if(DEBUG) { System.err.println("RegisteredClassFactory getSharedClass ("+sharedRefCount+") initialized: "+sharedClass); } @@ -113,10 +121,7 @@ public class RegisteredClassFactory { throw new InternalError("Error ("+sharedRefCount+"): SharedClass is null"); } if( 0 == sharedRefCount ) { - GDI.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); - synchronized(sharedClasses) { - sharedClasses.remove(sharedClass); - } + GDIUtil.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); if(DEBUG) { System.err.println("RegisteredClassFactory releaseSharedClass ("+sharedRefCount+") released: "+sharedClass); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index b669bce75..268416266 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -33,10 +33,22 @@ package jogamp.nativewindow.x11; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, new X11GraphicsConfigurationFactory()); + } + private X11GraphicsConfigurationFactory() { + } + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) throws IllegalArgumentException, NativeWindowException { @@ -55,7 +67,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor int num[] = { -1 }; long display = screen.getDevice().getHandle(); - XVisualInfo[] xvis = X11Util.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); + XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); if(xvis==null || num[0]<1) { return null; @@ -81,7 +93,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor vinfo_template.setC_class(c_class); long display = screen.getDevice().getHandle(); - XVisualInfo[] vinfos = X11Util.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); + XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); XVisualInfo best=null; int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); for (int i = 0; vinfos!=null && i < num[0]; i++) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java index fb0aff10d..5166ef577 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java @@ -29,6 +29,9 @@ package jogamp.nativewindow.x11; import javax.media.nativewindow.ToolkitLock; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + /** * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} * utilizing {@link X11Util#XLockDisplay(long)}. @@ -38,18 +41,30 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11ToolkitLock implements ToolkitLock { long displayHandle; + RecursiveLock lock; public X11ToolkitLock(long displayHandle) { this.displayHandle = displayHandle; + if(!X11Util.isNativeLockAvailable()) { + lock = LockFactory.createRecursiveLock(); + } } public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock()"); } - X11Util.XLockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XLockDisplay(displayHandle); + } else { + lock.lock(); + } } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock()"); } - X11Util.XUnlockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XUnlockDisplay(displayHandle); + } else { + lock.unlock(); + } } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 5c1839250..560130dd1 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -33,19 +33,18 @@ package jogamp.nativewindow.x11; -import com.jogamp.common.util.LongObjectHashMap; -import jogamp.nativewindow.Debug; -import jogamp.nativewindow.NWJNILibLoader; - -import javax.media.nativewindow.*; - -import java.nio.Buffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; import java.security.AccessController; import java.util.ArrayList; import java.util.List; -import javax.media.nativewindow.util.Point; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NWJNILibLoader; + +import com.jogamp.common.util.LongObjectHashMap; /** * Contains a thread safe X11 utility to retrieve display connections. @@ -53,54 +52,88 @@ import javax.media.nativewindow.util.Point; public class X11Util { /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 - * - * It is observed that ATI X11 drivers, eg. fglrx 8.78.6 and fglrx 11.08/8.881, + * <p> + * It is observed that ATI X11 drivers, eg. + * <ul> + * <li>fglrx 8.78.6,</li> + * <li>fglrx 11.08/8.881 and </li> + * <li>fglrx 11.11/8.911</li> + * </ul> * are quite sensitive to multiple Display connections. - * Here, closing displays shall happen in the same order as - * they were opened, -OR- shall not be closed at all! - * Otherwise some driver related bug appears and brings down the JVM. + * </p> + * <p> + * With the above drivers closing displays shall happen in the same order as + * they were opened, <b>or</b> shall not be closed at all! + * If closed, some driver related bug appears and brings down the JVM. + * </p> + * <p> * You may test this, ie just reverse the destroy order below. * See also native test: jogl/test/native/displayMultiple02.c - * - * Our current 'workaround' is to not close them at all if driver vendor is ATI. + * </p> + * <p> + * Workaround is to not close them at all if driver vendor is ATI. + * </p> */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = true; - - public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; + /** Value is <code>true</code>, best 'stable' results if always using XInitThreads(). */ + public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; + + /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ + public static final boolean HAS_XLOCKDISPLAY_BUG = true; + private static final boolean DEBUG = Debug.debug("X11Util"); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.getBooleanProperty("nativewindow.debug.X11Util.TraceDisplayLifecycle", true, AccessController.getContext()); - private static volatile String nullDisplayName = null; - private static boolean requiresX11Lock = false; - private static boolean isInit = false; + private static String nullDisplayName = null; + private static boolean isX11LockAvailable = false; + private static boolean requiresX11Lock = true; + private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues private static int setX11ErrorHandlerRecCount = 0; private static Object setX11ErrorHandlerLock = new Object(); - public static synchronized void initSingleton(final boolean firstX11ActionOnProcess) { + @SuppressWarnings("unused") + public static void initSingleton(final boolean firstX11ActionOnProcess) { if(!isInit) { - NWJNILibLoader.loadNativeWindow("x11"); - - /** - * Always issue XInitThreads() since we have independent - * off-thread created Display connections able to utilize multithreading, - * ie NEWT (jogamp.newt.x11.X11Display.createNativeImpl()) !! - */ - initialize0( XINITTHREADS_ALWAYS_ENABLED ? true : firstX11ActionOnProcess ); - - requiresX11Lock = !firstX11ActionOnProcess ; - - if(DEBUG) { - System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+ - ", XINITTHREADS_ALWAYS_ENABLED "+XINITTHREADS_ALWAYS_ENABLED+ - ", requiresX11Lock "+requiresX11Lock); + synchronized(X11Util.class) { + if(!isInit) { + isInit = true; + NWJNILibLoader.loadNativeWindow("x11"); + + final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess; + final boolean isXInitThreadsOK = initialize0( XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess ); + isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; + + final long dpy = X11Lib.XOpenDisplay(null); + try { + nullDisplayName = X11Lib.XDisplayString(dpy); + } finally { + X11Lib.XCloseDisplay(dpy); + } + + if(DEBUG) { + System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+ + ", requiresX11Lock "+requiresX11Lock+ + ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ + ", isX11LockAvailable "+isX11LockAvailable+ + ", X11 Display(NULL) <"+nullDisplayName+">"); + // Thread.dumpStack(); + } + } } - isInit = true; } } + + public static synchronized boolean isNativeLockAvailable() { + return isX11LockAvailable; + } + + public static synchronized boolean requiresToolkitLock() { + return requiresX11Lock; + } public static void setX11ErrorHandler(boolean onoff, boolean quiet) { synchronized(setX11ErrorHandlerLock) { @@ -121,42 +154,7 @@ public class X11Util { } } - public static boolean requiresToolkitLock() { - return requiresX11Lock; - } - - public static void lockDefaultToolkit(long dpyHandle) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - if(requiresX11Lock) { - X11Util.XLockDisplay(dpyHandle); - } - } - - public static void unlockDefaultToolkit(long dpyHandle) { - if(requiresX11Lock) { - X11Util.XUnlockDisplay(dpyHandle); - } - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - public static String getNullDisplayName() { - if(null==nullDisplayName) { // volatile: ok - synchronized(X11Util.class) { - if(null==nullDisplayName) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - long dpy = X11Lib.XOpenDisplay(null); - try { - nullDisplayName = X11Lib.XDisplayString(dpy); - } finally { - X11Lib.XCloseDisplay(dpy); - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - if(DEBUG) { - System.out.println("X11 Display(NULL) <"+nullDisplayName+">"); - } - } - } - } return nullDisplayName; } @@ -224,7 +222,6 @@ public class X11Util { public final void setUncloseable(boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } - public final Throwable getCreationStack() { return creationStack; } @Override @@ -238,20 +235,22 @@ public class X11Util { } } - /** Returns the number of unclosed X11 Displays. + /** + * Cleanup resources. + * If <code>realXCloseOpenAndPendingDisplays</code> is <code>false</code>, + * keep alive all references (open display connection) for restart on same ClassLoader. + * + * @return number of unclosed X11 Displays.<br> * @param realXCloseOpenAndPendingDisplays if true, {@link #closePendingDisplayConnections()} is called. - */ + */ public static int shutdown(boolean realXCloseOpenAndPendingDisplays, boolean verbose) { int num=0; if(DEBUG||verbose||pendingDisplayList.size() > 0) { - String msg = "X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ - ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ - ", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")" ; + System.err.println("X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ + ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ + ", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")"); if(DEBUG) { - Exception e = new Exception(msg); - e.printStackTrace(); - } else { - System.err.println(msg); + Thread.dumpStack(); } if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); @@ -264,10 +263,11 @@ public class X11Util { synchronized(globalLock) { if(realXCloseOpenAndPendingDisplays) { closePendingDisplayConnections(); + openDisplayList.clear(); + pendingDisplayList.clear(); + openDisplayMap.clear(); + shutdown0(); } - openDisplayList.clear(); - pendingDisplayList.clear(); - openDisplayMap.clear(); } return num; } @@ -304,9 +304,9 @@ public class X11Util { public static void dumpOpenDisplayConnections() { synchronized(globalLock) { System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size()); - for(int i=0; i<pendingDisplayList.size(); i++) { + for(int i=0; i<openDisplayList.size(); i++) { NamedDisplay ndpy = openDisplayList.get(i); - System.err.println("X11Util: ["+i+"]: "+ndpy); + System.err.println("X11Util: Open["+i+"]: "+ndpy); if(null!=ndpy) { Throwable t = ndpy.getCreationStack(); if(null!=t) { @@ -316,7 +316,7 @@ public class X11Util { } } } - + public static int getPendingDisplayConnectionNumber() { synchronized(globalLock) { return pendingDisplayList.size(); @@ -328,7 +328,7 @@ public class X11Util { System.err.println("X11Util: Pending X11 Display Connections: "+pendingDisplayList.size()); for(int i=0; i<pendingDisplayList.size(); i++) { NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); - System.err.println("X11Util: ["+i+"]: "+ndpy); + System.err.println("X11Util: Pending["+i+"]: "+ndpy); if(null!=ndpy) { Throwable t = ndpy.getCreationStack(); if(null!=t) { @@ -384,8 +384,8 @@ public class X11Util { } } if(DEBUG) { - Exception e = new Exception("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); - e.printStackTrace(); + System.err.println("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); + // Thread.dumpStack(); } return namedDpy.getHandle(); } @@ -408,10 +408,6 @@ public class X11Util { if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } if(!namedDpy.isUncloseable()) { - if(DEBUG) { - System.err.println("X11Util.Display: XCloseDisplay "+namedDpy+". Thread "+Thread.currentThread().getName()); - Thread.dumpStack(); - } XCloseDisplay(namedDpy.getHandle()); } else { // for reuse @@ -439,7 +435,7 @@ public class X11Util { public static String validateDisplayName(String name, long handle) { if( ( null==name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) && 0!=handle) { - name = XDisplayString(handle); + name = X11Lib.XDisplayString(handle); } return validateDisplayName(name); } @@ -455,8 +451,8 @@ public class X11Util { try { long handle = X11Lib.XOpenDisplay(arg0); if(TRACE_DISPLAY_LIFECYCLE) { - Throwable t = new Throwable(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - t.printStackTrace(); + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); } return handle; } finally { @@ -468,8 +464,8 @@ public class X11Util { NativeWindowFactory.getDefaultToolkitLock().lock(); try { if(TRACE_DISPLAY_LIFECYCLE) { - Throwable t = new Throwable(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - t.printStackTrace(); + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); } int res = -1; X11Util.setX11ErrorHandler(true, DEBUG ? false : true); @@ -487,209 +483,7 @@ public class X11Util { } } - public static int XFree(Buffer arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - return X11Lib.XFree(arg0); - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - } - - public static int XSync(long display, boolean discard) { - lockDefaultToolkit(display); - try { - return X11Lib.XSync(display, discard); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void XSynchronize(long display, boolean onoff) { - lockDefaultToolkit(display); - try { - X11Lib.XSynchronize(display, onoff); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XineramaEnabled(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XineramaEnabled(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int DefaultScreen(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.DefaultScreen(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long RootWindow(long display, int screen_number) { - lockDefaultToolkit(display); - try { - return X11Lib.RootWindow(display, screen_number); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long XCreatePixmap(long display, long arg1, int arg2, int arg3, int arg4) { - lockDefaultToolkit(display); - try { - return X11Lib.XCreatePixmap(display, arg1, arg2, arg3, arg4); - } finally { - unlockDefaultToolkit(display); - } - } - - public static String XDisplayString(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XDisplayString(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int XFlush(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XFlush(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int XFreePixmap(long display, long arg1) { - lockDefaultToolkit(display); - try { - return X11Lib.XFreePixmap(display, arg1); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long DefaultVisualID(long display, int screen) { - lockDefaultToolkit(display); - try { - return X11Lib.DefaultVisualID(display, screen); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long CreateDummyWindow(long display, int screen_index, long visualID, int width, int height) { - lockDefaultToolkit(display); - try { - return X11Lib.CreateDummyWindow(display, screen_index, visualID, width, height); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void DestroyDummyWindow(long display, long window) { - lockDefaultToolkit(display); - try { - X11Lib.DestroyDummyWindow(display, window); - } finally { - unlockDefaultToolkit(display); - } - } - - public static Point GetRelativeLocation(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y) { - lockDefaultToolkit(display); - try { - return X11Lib.GetRelativeLocation(display, screen_index, src_win, dest_win, src_x, src_y); - } finally { - unlockDefaultToolkit(display); - } - } - - public static XVisualInfo[] XGetVisualInfo(long display, long arg1, XVisualInfo arg2, int[] arg3, int arg3_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XGetVisualInfo(display, arg1, arg2, arg3, arg3_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, green_array, blue_array); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, short[] red_array, int red_array_offset, short[] green_array, int green_array_offset, short[] blue_array, int blue_array_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRampSize(long display, int screen, IntBuffer size) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRampSize(long display, int screen, int[] size, int size_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size, size_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, green_array, blue_array); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, short[] red_array, int red_array_offset, short[] green_array, int green_array_offset, short[] blue_array, int blue_array_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void XLockDisplay(long handle) { - if(ToolkitLock.TRACE_LOCK) { - System.out.println("+++ X11 Display Lock get 0x"+Long.toHexString(handle)); - } - X11Lib.XLockDisplay(handle); - } - - public static void XUnlockDisplay(long handle) { - if(ToolkitLock.TRACE_LOCK) { - System.out.println("--- X11 Display Lock rel 0x"+Long.toHexString(handle)); - } - X11Lib.XUnlockDisplay(handle); - } - - private static native void initialize0(boolean firstUIActionOnProcess); + private static native boolean initialize0(boolean firstUIActionOnProcess); + private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java new file mode 100644 index 000000000..efaf4728c --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package jogamp.nativewindow.x11.awt; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ToolkitLock; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; +import javax.media.nativewindow.awt.AWTGraphicsDevice; +import javax.media.nativewindow.awt.AWTGraphicsScreen; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsDevice; +import javax.media.nativewindow.x11.X11GraphicsScreen; + +import jogamp.nativewindow.jawt.x11.X11SunJDKReflection; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; + +public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory { + + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, new X11AWTGraphicsConfigurationFactory()); + } + private X11AWTGraphicsConfigurationFactory() { + } + + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { + if (absScreen != null && + !(absScreen instanceof AWTGraphicsScreen)) { + throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects"); + } + if(null==absScreen) { + absScreen = AWTGraphicsScreen.createDefault(); + } + + return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen); + } + + public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic( + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen) { + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen); + } + + final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); + + long displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(device); + boolean owner = false; + if(0==displayHandle) { + displayHandle = X11Util.openDisplay(null); + owner = true; + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - X11AWTGraphicsConfigurationFactory: create local X11 display"); + } + } else { + /** + * Using the AWT display handle works fine with NVidia. + * However we experienced different results w/ AMD drivers, + * some work, but some behave erratic. + * I.e. hangs in XQueryExtension(..) via X11GraphicsScreen. + */ + final String displayName = X11Lib.XDisplayString(displayHandle); + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - X11AWTGraphicsConfigurationFactory: create X11 display @ "+displayName+" / 0x"+Long.toHexString(displayHandle)); + } + displayHandle = X11Util.openDisplay(displayName); + owner = true; + } + final ToolkitLock lock = owner ? + NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock + NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle); + final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); + final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen); + } + + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device); + X11GraphicsConfiguration x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + if (x11Config == null) { + throw new NativeWindowException("Unable to choose a GraphicsConfiguration (1): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); + } + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: chosen x11Config: "+x11Config); + } + + // + // Match the X11/GL Visual with AWT: + // - choose a config AWT agnostic and then + // - try to find the visual within the GraphicsConfiguration + // + // The resulting GraphicsConfiguration has to be 'forced' on the AWT native peer, + // ie. returned by GLCanvas's getGraphicsConfiguration() befor call by super.addNotify(). + // + final GraphicsConfiguration[] configs = device.getConfigurations(); + long visualID = x11Config.getVisualID(); + for (int i = 0; i < configs.length; i++) { + GraphicsConfiguration gc = configs[i]; + if (gc != null) { + if (X11SunJDKReflection.graphicsConfigurationGetVisualID(gc) == visualID) { + if(DEBUG) { + System.err.println("Found matching AWT visual: 0x"+Long.toHexString(visualID) +" -> "+x11Config); + } + return new AWTGraphicsConfiguration(awtScreen, + x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), + gc, x11Config); + } + } + } + + // try again using an AWT Colormodel compatible configuration + GraphicsConfiguration gc = device.getDefaultConfiguration(); + capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsChosen, gc); + x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + if (x11Config == null) { + throw new NativeWindowException("Unable to choose a GraphicsConfiguration (2): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); + } + visualID = x11Config.getVisualID(); + for (int i = 0; i < configs.length; i++) { + gc = configs[i]; + if (X11SunJDKReflection.graphicsConfigurationGetVisualID(gc) == visualID) { + if(DEBUG) { + System.err.println("Found matching default AWT visual: 0x"+Long.toHexString(visualID) +" -> "+x11Config); + } + return new AWTGraphicsConfiguration(awtScreen, + x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), + gc, x11Config); + } + } + + // Either we weren't able to reflectively introspect on the + // X11GraphicsConfig or something went wrong in the steps above; + // Let's take the default configuration as used on Windows and MacOSX then .. + if(DEBUG) { + System.err.println("!!! Using default configuration"); + } + + gc = device.getDefaultConfiguration(); + return new AWTGraphicsConfiguration(awtScreen, x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), gc, x11Config); + } +} + diff --git a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c index 470f03a49..2a6651007 100644 --- a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c +++ b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c @@ -59,6 +59,13 @@ Java_jogamp_nativewindow_jawt_JAWT_1DrawingSurfaceInfo_platformInfo0(JNIEnv* env return NULL; } if (dsi->platformInfo == NULL) { + (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), + "platformInfo pointer is NULL"); + return NULL; + } + if(0==PLATFORM_DSI_SIZE) { + (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), + "platformInfo size is 0"); return NULL; } return (*env)->NewDirectByteBuffer(env, dsi->platformInfo, PLATFORM_DSI_SIZE); diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index e19d5ecf7..d64973b67 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -35,6 +35,19 @@ #include "NativewindowCommon.h" #include "jogamp_nativewindow_macosx_OSXUtil.h" +#include "jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow.h" + +#include <jawt_md.h> +#import <JavaNativeFoundation.h> + +// #define VERBOSE 1 +// +#ifdef VERBOSE + // #define DBG_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif static const char * const ClazzNameRunnable = "java/lang/Runnable"; static jmethodID runnableRunID = NULL; @@ -81,7 +94,7 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: getLocationOnScreenImpl0 + * Method: getLocationOnScreen0 * Signature: (JII)Ljavax/media/nativewindow/util/Point; */ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnScreen0 @@ -97,7 +110,7 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS int dest_x=-1; int dest_y=-1; - NSObject *nsObj = (NSObject*) ((intptr_t) winOrView); + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; NSWindow* win = NULL; NSView* view = NULL; @@ -135,6 +148,189 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS return res; } +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: CreateNSView0 + * Signature: (IIIIZ)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSView0 + (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSRect rect = NSMakeRect(x, y, width, height); + NSView * view = [[NSView alloc] initWithFrame: rect] ; + [view setCanDrawConcurrently: YES]; + [pool release]; + + return (jlong) (intptr_t) view; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: DestroyNSView0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSView0 + (JNIEnv *env, jclass unused, jlong nsView) +{ + NSView* view = (NSView*) (intptr_t) nsView; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [view release]; + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: CreateNSWindow0 + * Signature: (IIIIZ)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0 + (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSRect rect = NSMakeRect(x, y, width, height); + + // Allocate the window + NSWindow* myWindow = [[NSWindow alloc] initWithContentRect: rect + styleMask: NSBorderlessWindowMask + backing: NSBackingStoreBuffered + defer: YES]; + [myWindow setReleasedWhenClosed: YES]; // default + [myWindow setPreservesContentDuringLiveResize: YES]; + + // invisible .. + [myWindow setOpaque: NO]; + [myWindow setBackgroundColor: [NSColor clearColor]]; + + [pool release]; + + return (jlong) ((intptr_t) myWindow); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: DestroyNSWindow0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSWindow0 + (JNIEnv *env, jclass unused, jlong nsWindow) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* mWin = (NSWindow*) ((intptr_t) nsWindow); + + [mWin close]; // performs release! + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: CreateCALayer0 + * Signature: (V)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 + (JNIEnv *env, jclass unused) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + // CALayer* layer = [[CALayer alloc] init]; + CALayer* layer = [CALayer layer]; + + // no animations for add/remove/swap sublayers etc + [layer removeAnimationForKey: kCAOnOrderIn]; + [layer removeAnimationForKey: kCAOnOrderOut]; + [layer removeAnimationForKey: kCATransition]; + + // initial dummy size ! + CGRect lRect = [layer frame]; + lRect.origin.x = 0; + lRect.origin.y = 0; + lRect.size.width = 32; + lRect.size.height = 32; + [layer setFrame: lRect]; + DBG_PRINT("CALayer::CreateCALayer0: %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + + [pool release]; + + return (jlong) ((intptr_t) layer); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: AddCASublayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) +{ + JNF_COCOA_ENTER(env); + CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + CGRect lRectRoot = [rootLayer frame]; + DBG_PRINT("CALayer::AddCASublayer0.0: Origin %p frame0: %lf/%lf %lfx%lf\n", + rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + if(lRectRoot.origin.x<0 || lRectRoot.origin.y<0) { + lRectRoot.origin.x = 0; + lRectRoot.origin.y = 0; + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [rootLayer setFrame: lRectRoot]; + }]; + DBG_PRINT("CALayer::AddCASublayer0.1: Origin %p frame*: %lf/%lf %lfx%lf\n", + rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + } + DBG_PRINT("CALayer::AddCASublayer0.2: %p . %p %lf/%lf %lfx%lf (refcnt %d)\n", + rootLayer, subLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (int)[subLayer retainCount]); + + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + // simple 1:1 layout ! + [subLayer setFrame:lRectRoot]; + [rootLayer addSublayer:subLayer]; + }]; + DBG_PRINT("CALayer::AddCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); + JNF_COCOA_EXIT(env); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: RemoveCASublayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) +{ + JNF_COCOA_ENTER(env); + CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + (void)rootLayer; // no warnings + + DBG_PRINT("CALayer::RemoveCASublayer0.0: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [subLayer removeFromSuperlayer]; + }]; + DBG_PRINT("CALayer::RemoveCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); + JNF_COCOA_EXIT(env); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: DestroyCALayer0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 + (JNIEnv *env, jclass unused, jlong caLayer) +{ + JNF_COCOA_ENTER(env); + CALayer* layer = (CALayer*) ((intptr_t) caLayer); + + DBG_PRINT("CALayer::DestroyCALayer0.0: %p (refcnt %d)\n", layer, (int)[layer retainCount]); + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [layer release]; // performs release! + }]; + DBG_PRINT("CALayer::DestroyCALayer0.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); + JNF_COCOA_EXIT(env); +} + @interface MainRunnable : NSObject { @@ -212,10 +408,35 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: RunOnMainThread0 - * Signature: (ZLjava/lang/Runnable;)V + * Signature: (V)V */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 (JNIEnv *env, jclass unused) { return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ; } + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: AttachJAWTSurfaceLayer + * Signature: (JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_AttachJAWTSurfaceLayer0 + (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) +{ + JNF_COCOA_ENTER(env); + JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); + if (NULL == dsi) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); + return JNI_FALSE; + } + CALayer* layer = (CALayer*) (intptr_t) caLayer; + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; + DBG_PRINT("CALayer::attachJAWTSurfaceLayer: %p -> %p\n", surfaceLayers.layer, layer); + surfaceLayers.layer = [layer autorelease]; + }]; + JNF_COCOA_EXIT(env); + return JNI_TRUE; +} + diff --git a/src/nativewindow/native/windows/GDImisc.c b/src/nativewindow/native/windows/GDImisc.c index e8285008e..3ab7f9859 100644 --- a/src/nativewindow/native/windows/GDImisc.c +++ b/src/nativewindow/native/windows/GDImisc.c @@ -14,7 +14,7 @@ #include <stdio.h> #include "NativewindowCommon.h" -#include "jogamp_nativewindow_windows_GDI.h" +#include "jogamp_nativewindow_windows_GDIUtil.h" // #define VERBOSE_ON 1 @@ -36,12 +36,12 @@ HINSTANCE GetApplicationHandle() { } /* Java->C glue code: - * Java package: jogamp.nativewindow.windows.GDI + * Java package: jogamp.nativewindow.windows.GDIUtil * Java method: boolean CreateWindowClass(long hInstance, java.lang.String clazzName, long wndProc) * C function: BOOL CreateWindowClass(HANDLE hInstance, LPCSTR clazzName, HANDLE wndProc); */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDI_CreateWindowClass +Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName, jlong wndProc) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; @@ -85,12 +85,12 @@ Java_jogamp_nativewindow_windows_GDI_CreateWindowClass } /* Java->C glue code: - * Java package: jogamp.nativewindow.windows.GDI + * Java package: jogamp.nativewindow.windows.GDIUtil * Java method: boolean DestroyWindowClass(long hInstance, java.lang.String className) * C function: BOOL DestroyWindowClass(HANDLE hInstance, LPCSTR className); */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDI_DestroyWindowClass +Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; @@ -116,12 +116,12 @@ Java_jogamp_nativewindow_windows_GDI_DestroyWindowClass /* Java->C glue code: - * Java package: jogamp.nativewindow.windows.GDI + * Java package: jogamp.nativewindow.windows.GDIUtil * Java method: long CreateDummyWindow0(long hInstance, java.lang.String className, java.lang.String windowName, int x, int y, int width, int height) * C function: HANDLE CreateDummyWindow0(HANDLE hInstance, LPCSTR className, LPCSTR windowName, int x, int y, int width, int height); */ JNIEXPORT jlong JNICALL -Java_jogamp_nativewindow_windows_GDI_CreateDummyWindow0 +Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyWindow0 (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jWndClassName, jstring jWndName, jint x, jint y, jint width, jint height) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; @@ -162,26 +162,26 @@ Java_jogamp_nativewindow_windows_GDI_CreateDummyWindow0 /* - * Class: jogamp_nativewindow_windows_GDI + * Class: jogamp_nativewindow_windows_GDIUtil * Method: initIDs0 * Signature: ()Z */ -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDI_initIDs0 +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 (JNIEnv *env, jclass clazz) { if(NativewindowCommon_init(env)) { jclass c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDI: can't find %s", ClazzNamePoint); + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't find %s", ClazzNamePoint); } pointClz = (jclass)(*env)->NewGlobalRef(env, c); (*env)->DeleteLocalRef(env, c); if(NULL==pointClz) { - NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDI: can't use %s", ClazzNamePoint); + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't use %s", ClazzNamePoint); } pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); if(NULL==pointCstr) { - NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDI: can't fetch %s.%s %s", + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't fetch %s.%s %s", ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } } @@ -193,22 +193,22 @@ LRESULT CALLBACK DummyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l } /* - * Class: jogamp_nativewindow_windows_GDI + * Class: jogamp_nativewindow_windows_GDIUtil * Method: getDummyWndProc0 * Signature: ()J */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_windows_GDI_getDummyWndProc0 +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_windows_GDIUtil_getDummyWndProc0 (JNIEnv *env, jclass clazz) { return (jlong) (intptr_t) DummyWndProc; } /* - * Class: jogamp_nativewindow_windows_GDI + * Class: jogamp_nativewindow_windows_GDIUtil * Method: GetRelativeLocation0 * Signature: (JJII)Ljavax/media/nativewindow/util/Point; */ -JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_windows_GDI_GetRelativeLocation0 +JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_windows_GDIUtil_GetRelativeLocation0 (JNIEnv *env, jclass unused, jlong jsrc_win, jlong jdest_win, jint src_x, jint src_y) { HWND src_win = (HWND) (intptr_t) jsrc_win; diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index d481343f9..d28891cda 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -293,14 +293,16 @@ static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { } static int _initialized=0; +static jboolean _xinitThreadsOK=JNI_FALSE; -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass _unused, jboolean firstUIActionOnProcess) { if(0==_initialized) { if( JNI_TRUE == firstUIActionOnProcess ) { if( 0 == XInitThreads() ) { fprintf(stderr, "Warning: XInitThreads() failed\n"); } else { + _xinitThreadsOK=JNI_TRUE; fprintf(stderr, "Info: XInitThreads() called for concurrent Thread support\n"); } } else { @@ -311,6 +313,12 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass _unused, jb x11IOErrorHandlerEnable(1, env); _initialized=1; } + return _xinitThreadsOK; +} + +JNIEXPORT void JNICALL +Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { + x11IOErrorHandlerEnable(0, env); } JNIEXPORT void JNICALL |