/* * Copyright (c) 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * 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 com.jogamp.nativewindow; import java.io.File; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import com.jogamp.nativewindow.util.PointImmutable; import jogamp.common.os.PlatformPropsImpl; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NativeWindowFactoryImpl; import jogamp.nativewindow.ToolkitProperties; import jogamp.nativewindow.ResourceToolkitLock; import jogamp.nativewindow.WrappedWindow; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import com.jogamp.common.os.Platform; import com.jogamp.common.util.InterruptSource; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; /** Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the {@link NativeWindow} interface, which provides a platform-independent mechanism of accessing the information required to perform operations like hardware-accelerated rendering using the OpenGL API. * <p> * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation * </p> */ public abstract class NativeWindowFactory { protected static final boolean DEBUG; /** OpenKODE/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ public static final String TYPE_EGL = ".egl".intern(); /** Microsoft Windows type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_WINDOWS = ".windows".intern(); /** X11 type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_X11 = ".x11".intern(); /** Broadcom VC IV/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_BCM_VC_IV = ".bcm.vc.iv".intern(); /** Android/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ public static final String TYPE_ANDROID = ".android".intern(); /** Mac OS X type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_MACOSX = ".macosx".intern(); /** Generic AWT type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_AWT = ".awt".intern(); /** Generic DEFAULT type, where platform implementation don't care, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_DEFAULT = ".default".intern(); private static final String nativeWindowingTypePure; // canonical String via String.intern() private static final String nativeWindowingTypeCustom; // canonical String via String.intern() private static NativeWindowFactory defaultFactory; private static Map<Class<?>, NativeWindowFactory> registeredFactories; private static Class<?> nativeWindowClass; private static boolean isAWTAvailable; private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; /** {@link jogamp.nativewindow.x11.X11Util} implements {@link ToolkitProperties}. */ private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; /** {@link jogamp.nativewindow.macosx.OSXUtil} implements {@link ToolkitProperties}. */ private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; /** {@link jogamp.nativewindow.windows.GDIUtil} implements {@link ToolkitProperties}. */ private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; private static ToolkitLock jawtUtilJAWTToolkitLock; private static boolean requiresToolkitLock; private static boolean desktopHasThreadingIssues; // Shutdown hook mechanism for the factory private static volatile boolean isJVMShuttingDown = false; private static final List<Runnable> customShutdownHooks = new ArrayList<Runnable>(); /** Creates a new NativeWindowFactory instance. End users do not need to call this method. */ protected NativeWindowFactory() { } private static final boolean guessBroadcomVCIV() { return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { private final File vcliblocation = new File( "/opt/vc/lib/libbcm_host.so"); @Override public Boolean run() { if ( vcliblocation.isFile() ) { return Boolean.TRUE; } return Boolean.FALSE; } } ).booleanValue(); } private static String _getNativeWindowingType() { switch(PlatformPropsImpl.OS_TYPE) { case ANDROID: return TYPE_ANDROID; case MACOS: return TYPE_MACOSX; case WINDOWS: return TYPE_WINDOWS; case OPENKODE: return TYPE_EGL; case LINUX: case FREEBSD: case SUNOS: case HPUX: default: if( guessBroadcomVCIV() ) { return TYPE_BCM_VC_IV; } return TYPE_X11; } } static { final boolean[] _DEBUG = new boolean[] { false }; final String[] _tmp = new String[] { null }; AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { Platform.initSingleton(); // last resort .. _DEBUG[0] = Debug.debug("NativeWindow"); _tmp[0] = PropertyAccess.getProperty("nativewindow.ws.name", true); Runtime.getRuntime().addShutdownHook( new InterruptSource.Thread(null, new Runnable() { @Override public void run() { NativeWindowFactory.shutdown(true); } }, "NativeWindowFactory_ShutdownHook" ) ) ; return null; } } ) ; DEBUG = _DEBUG[0]; if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - Info: NativeWindowFactory.<init>"); // Thread.dumpStack(); } // Gather the windowing TK first nativeWindowingTypePure = _getNativeWindowingType(); if(null==_tmp[0] || _tmp[0].length()==0) { nativeWindowingTypeCustom = nativeWindowingTypePure; } else { nativeWindowingTypeCustom = _tmp[0].intern(); // canonical representation } } private static boolean initialized = false; private static void initSingletonNativeImpl(final ClassLoader cl) { final String clazzName; if( TYPE_X11 == nativeWindowingTypePure ) { clazzName = X11UtilClassName; } else if( TYPE_WINDOWS == nativeWindowingTypePure ) { clazzName = GDIClassName; } else if( TYPE_MACOSX == nativeWindowingTypePure ) { clazzName = OSXUtilClassName; } else { clazzName = null; } if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "initSingleton", null, null, cl ); final Boolean res1 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl); requiresToolkitLock = res1.booleanValue(); final Boolean res2 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "hasThreadingIssues", null, null, cl); desktopHasThreadingIssues = res2.booleanValue(); } else { requiresToolkitLock = false; desktopHasThreadingIssues = false; } } /** Returns true if the JVM is shutting down, otherwise false. */ public static final boolean isJVMShuttingDown() { return isJVMShuttingDown; } /** * Add a custom shutdown hook to be performed at JVM shutdown before shutting down NativeWindowFactory instance. * * @param head if true add runnable at the start, otherwise at the end * @param runnable runnable to be added. */ public static void addCustomShutdownHook(final boolean head, final Runnable runnable) { synchronized( customShutdownHooks ) { if( !customShutdownHooks.contains( runnable ) ) { if( head ) { customShutdownHooks.add(0, runnable); } else { customShutdownHooks.add( runnable ); } } } } /** * Cleanup resources at JVM shutdown */ public static synchronized void shutdown(final boolean _isJVMShuttingDown) { isJVMShuttingDown = _isJVMShuttingDown; if(DEBUG) { System.err.println("NativeWindowFactory.shutdown() START: JVM Shutdown "+isJVMShuttingDown+", on thread "+Thread.currentThread().getName()); } synchronized(customShutdownHooks) { final int cshCount = customShutdownHooks.size(); for(int i=0; i < cshCount; i++) { try { if( DEBUG ) { System.err.println("NativeWindowFactory.shutdown - customShutdownHook #"+(i+1)+"/"+cshCount); } customShutdownHooks.get(i).run(); } catch(final Throwable t) { System.err.println("NativeWindowFactory.shutdown: Caught "+t.getClass().getName()+" during customShutdownHook #"+(i+1)+"/"+cshCount); if( DEBUG ) { t.printStackTrace(); } } } customShutdownHooks.clear(); } if(DEBUG) { System.err.println("NativeWindowFactory.shutdown(): Post customShutdownHook"); } if(initialized) { initialized = false; if(null != registeredFactories) { registeredFactories.clear(); registeredFactories = null; } GraphicsConfigurationFactory.shutdown(); } shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown // SharedResourceToolkitLock.shutdown(DEBUG); // not used yet if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown); } } private static void shutdownNativeImpl(final ClassLoader cl) { final String clazzName; if( TYPE_X11 == nativeWindowingTypePure ) { clazzName = X11UtilClassName; } else if( TYPE_WINDOWS == nativeWindowingTypePure ) { clazzName = GDIClassName; } else if( TYPE_MACOSX == nativeWindowingTypePure ) { clazzName = OSXUtilClassName; } else { clazzName = null; } if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "shutdown", null, null, cl ); } } /** Returns true if {@link #initSingleton()} has been called w/o subsequent {@link #shutdown(boolean)}. */ public static synchronized boolean isInitialized() { return initialized; } /** * Static one time initialization of this factory.<br> * This initialization method <b>must be called</b> once by the program or utilizing modules! */ public static synchronized void initSingleton() { if(!initialized) { initialized = true; if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.initSingleton()"); } final ClassLoader cl = NativeWindowFactory.class.getClassLoader(); isAWTAvailable = false; // may be set to true below if( Platform.AWT_AVAILABLE && ReflectionUtil.isClassAvailable("com.jogamp.nativewindow.awt.AWTGraphicsDevice", cl) ) { final Method[] jawtUtilMethods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { @Override public Method[] run() { try { final Class<?> _jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader()); final Method jawtUtilIsHeadlessMethod = _jawtUtilClass.getDeclaredMethod("isHeadlessMode", (Class[])null); jawtUtilIsHeadlessMethod.setAccessible(true); final Method jawtUtilInitMethod = _jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null); jawtUtilInitMethod.setAccessible(true); final Method jawtUtilGetJAWTToolkitLockMethod = _jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); jawtUtilGetJAWTToolkitLockMethod.setAccessible(true); return new Method[] { jawtUtilInitMethod, jawtUtilIsHeadlessMethod, jawtUtilGetJAWTToolkitLockMethod }; } catch (final Exception e) { if(DEBUG) { e.printStackTrace(); } } return null; } }); if(null != jawtUtilMethods) { final Method jawtUtilInitMethod = jawtUtilMethods[0]; final Method jawtUtilIsHeadlessMethod = jawtUtilMethods[1]; final Method jawtUtilGetJAWTToolkitLockMethod = jawtUtilMethods[2]; ReflectionUtil.callMethod(null, jawtUtilInitMethod); Object resO = ReflectionUtil.callMethod(null, jawtUtilIsHeadlessMethod); if(resO instanceof Boolean) { // AWT is only available in case all above classes are available // and AWT is not int headless mode isAWTAvailable = ((Boolean)resO).equals(Boolean.FALSE); } else { throw new RuntimeException("JAWTUtil.isHeadlessMode() didn't return a Boolean"); } resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitLockMethod); if(resO instanceof ToolkitLock) { jawtUtilJAWTToolkitLock = (ToolkitLock) resO; } else { throw new RuntimeException("JAWTUtil.getJAWTToolkitLock() didn't return a ToolkitLock"); } } } // X11 initialization after possible AWT initialization // This is performed post AWT initialization, allowing AWT to complete the same, // which may have been triggered before NativeWindow initialization. // This way behavior is more uniforms across configurations (Applet/RCP, applications, ..). initSingletonNativeImpl(cl); registeredFactories = Collections.synchronizedMap(new HashMap<Class<?>, NativeWindowFactory>()); // register our default factory -> NativeWindow final NativeWindowFactory factory = new NativeWindowFactoryImpl(); nativeWindowClass = com.jogamp.nativewindow.NativeWindow.class; registerFactory(nativeWindowClass, factory); defaultFactory = factory; if ( isAWTAvailable ) { // register either our default factory or (if exist) the X11/AWT one -> AWT Component registerFactory(ReflectionUtil.getClass(ReflectionUtil.AWTNames.ComponentClass, false, cl), factory); } if(DEBUG) { System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock+", desktopHasThreadingIssues "+desktopHasThreadingIssues); System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory); } GraphicsConfigurationFactory.initSingleton(); } } /** @return true if the underlying toolkit requires locking, otherwise false. */ public static boolean requiresToolkitLock() { return requiresToolkitLock; } /** @return true if not headless, AWT Component and NativeWindow's AWT part available */ public static boolean isAWTAvailable() { return isAWTAvailable; } /** * @param useCustom if false return the native value, if true return a custom value if set, otherwise fallback to the native value. * @return the native window type, e.g. {@link #TYPE_X11}, which is canonical via {@link String#intern()}. * Hence {@link String#equals(Object)} and <code>==</code> produce the same result. */ public static String getNativeWindowType(final boolean useCustom) { return useCustom?nativeWindowingTypeCustom:nativeWindowingTypePure; } /** Don't know if we shall add this factory here .. * <p> * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation * </p> public static AbstractGraphicsDevice createGraphicsDevice(String type, String connection, int unitID, long handle, ToolkitLock locker) { if(TYPE_EGL == type) { return new } else if(TYPE_X11 == type) { } else if(TYPE_WINDOWS == type) { } else if(TYPE_MACOSX == type)) { } else if(TYPE_AWT == type) { } else if(TYPE_DEFAULT == type) { } } */ /** Sets the default NativeWindowFactory. */ public static void setDefaultFactory(final NativeWindowFactory factory) { defaultFactory = factory; } /** Gets the default NativeWindowFactory. */ public static NativeWindowFactory getDefaultFactory() { return defaultFactory; } /** * Returns the AWT {@link ToolkitLock} (JAWT based) if {@link #isAWTAvailable}, otherwise null. * <p> * The JAWT based {@link ToolkitLock} also locks the global lock, * which matters if the latter is required. * </p> */ public static ToolkitLock getAWTToolkitLock() { return jawtUtilJAWTToolkitLock; } public static ToolkitLock getNullToolkitLock() { return NativeWindowFactoryImpl.getNullToolkitLock(); } /** * Provides the system default {@link ToolkitLock} for the default system windowing type. * @see #getNativeWindowType(boolean) * @see #getDefaultToolkitLock(java.lang.String) */ public static ToolkitLock getDefaultToolkitLock() { return getDefaultToolkitLock(nativeWindowingTypePure); } /** * Provides the default {@link ToolkitLock} for <code>type</code>. * <ul> * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li> * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock getDefaultToolkitLock(final String type) { if( requiresToolkitLock ) { if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()! return getAWTToolkitLock(); } return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } /** * Provides the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. * <ul> * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li> * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock getDefaultToolkitLock(final String type, final long deviceHandle) { if( requiresToolkitLock ) { if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()! return getAWTToolkitLock(); } return ResourceToolkitLock.create(); } return NativeWindowFactoryImpl.getNullToolkitLock(); } /** * @param device * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen * @return newly created AbstractGraphicsScreen matching device's native type */ public static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen) { final String type = device.getType(); if( TYPE_X11 == type ) { final X11GraphicsDevice x11Device = (X11GraphicsDevice)device; if(0 > screen) { screen = x11Device.getDefaultScreen(); } return new X11GraphicsScreen(x11Device, screen); } if(0 > screen) { screen = 0; // FIXME: Needs native API utilization } if( TYPE_AWT == type ) { final AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) device; return new AWTGraphicsScreen(awtDevice); } return new DefaultGraphicsScreen(device, screen); } /** Returns the appropriate NativeWindowFactory to handle window objects of the given type. The windowClass might be {@link NativeWindow NativeWindow}, in which case the client has already assumed the responsibility of creating a compatible NativeWindow implementation, or it might be that of a toolkit class like {@link java.awt.Component Component}. */ public static NativeWindowFactory getFactory(final Class<?> windowClass) throws IllegalArgumentException { if (nativeWindowClass.isAssignableFrom(windowClass)) { return registeredFactories.get(nativeWindowClass); } Class<?> clazz = windowClass; while (clazz != null) { final NativeWindowFactory factory = registeredFactories.get(clazz); if (factory != null) { return factory; } clazz = clazz.getSuperclass(); } throw new IllegalArgumentException("No registered NativeWindowFactory for class " + windowClass.getName()); } /** Registers a NativeWindowFactory handling window objects of the given class. This does not need to be called by end users, only implementors of new NativeWindowFactory subclasses. */ protected static void registerFactory(final Class<?> windowClass, final NativeWindowFactory factory) { if(DEBUG) { System.err.println("NativeWindowFactory.registerFactory() "+windowClass+" -> "+factory); } registeredFactories.put(windowClass, factory); } /** Converts the given window object and it's {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration} into a {@link NativeWindow NativeWindow} which can be operated upon by a custom toolkit, e.g. {@link com.jogamp.opengl.GLDrawableFactory com.jogamp.opengl.GLDrawableFactory}.<br> The object may be a component for a particular window toolkit, such as an AWT Canvas. It may also be a NativeWindow object itself.<br> You shall utilize {@link com.jogamp.nativewindow.GraphicsConfigurationFactory GraphicsConfigurationFactory} to construct a proper {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration}.<br> The particular implementation of the NativeWindowFactory is responsible for handling objects from a particular window toolkit. The built-in NativeWindowFactory handles NativeWindow instances as well as AWT Components.<br> @throws IllegalArgumentException if the given window object could not be handled by any of the registered NativeWindowFactory instances @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ public static NativeWindow getNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config) throws IllegalArgumentException, NativeWindowException { if (winObj == null) { throw new IllegalArgumentException("Null window object"); } return getFactory(winObj.getClass()).getNativeWindowImpl(winObj, config); } /** Performs the conversion from a toolkit's window object to a 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(final NativeSurface surface, final 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; } /** * Returns true if the given visualID is valid for further processing, i.e. OpenGL usage, * otherwise return false. * <p> * On certain platforms, i.e. X11, a valid visualID is required at window creation. * Other platforms may determine it later on, e.g. OSX and Windows. </p> * <p> * If the visualID is {@link VisualIDHolder#VID_UNDEFINED} and the platform requires it * at creation time (see above), it is not valid for further processing. * </p> * <p> * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation * </p> */ public static boolean isNativeVisualIDValidForProcessing(final int visualID) { return NativeWindowFactory.TYPE_X11 != NativeWindowFactory.getNativeWindowType(false) || VisualIDHolder.VID_UNDEFINED != visualID ; } public static String getDefaultDisplayConnection() { return getDefaultDisplayConnection(NativeWindowFactory.getNativeWindowType(true)); } public static String getDefaultDisplayConnection(final String nwt) { if(NativeWindowFactory.TYPE_X11 == nwt) { return X11Util.getNullDisplayName(); } else { return AbstractGraphicsDevice.DEFAULT_CONNECTION; } } /** * Creates a native device type, following {@link #getNativeWindowType(boolean) getNativeWindowType(true)}. * <p> * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired. * </p> */ public static AbstractGraphicsDevice createDevice(final String displayConnection, final boolean own) { return createDevice(NativeWindowFactory.getNativeWindowType(true), displayConnection, own); } /** * Creates a native device type, following the given {@link #getNativeWindowType(boolean) native-window-type}. * <p> * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired. * </p> * <p> * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation * </p> */ public static AbstractGraphicsDevice createDevice(final String nwt, final String displayConnection, final boolean own) { if( NativeWindowFactory.TYPE_X11 == nwt ) { if( own ) { return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT, null /* ToolkitLock */); } else { return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT); } } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } else if( NativeWindowFactory.TYPE_EGL == nwt ) { final EGLGraphicsDevice device; if( own ) { Object odev = null; try { // EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); odev = ReflectionUtil.callStaticMethod("jogamp.opengl.egl.EGLDisplayUtil", "eglCreateEGLGraphicsDevice", new Class<?>[] { Long.class, String.class, Integer.class}, new Object[] { 0L /* EGL.EGL_DEFAULT_DISPLAY */, DefaultGraphicsDevice.getDefaultDisplayConnection(nwt), AbstractGraphicsDevice.DEFAULT_UNIT }, NativeWindowFactory.class.getClassLoader()); } catch (final Exception e) { throw new NativeWindowException("EGLDisplayUtil.eglCreateEGLGraphicsDevice failed", e); } if( odev instanceof EGLGraphicsDevice ) { device = (EGLGraphicsDevice)odev; device.open(); } else { throw new NativeWindowException("EGLDisplayUtil.eglCreateEGLGraphicsDevice failed"); } } else { device = new EGLGraphicsDevice(0, 0 /* EGL.EGL_NO_DISPLAY */, displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT, null); } return device; } else if( NativeWindowFactory.TYPE_AWT == nwt ) { throw new UnsupportedOperationException("n/a for windowing system: "+nwt); } else { return new DefaultGraphicsDevice(nwt, displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT); } } /** * Creates a wrapped {@link NativeWindow} with given native handles and {@link AbstractGraphicsScreen}. * <p> * The given {@link UpstreamWindowHookMutableSizePos} maybe used to reflect resizes and repositioning of the native window. * </p> * <p> * The {@link AbstractGraphicsScreen} may be created via {@link #createScreen(AbstractGraphicsDevice, int)}. * </p> * <p> * The {@link AbstractGraphicsScreen} may have an underlying open {@link AbstractGraphicsDevice} * or a simple <i>dummy</i> instance, see {@link #createDevice(String, boolean)}. * </p> */ public static NativeWindow createWrappedWindow(final AbstractGraphicsScreen aScreen, final long surfaceHandle, final long windowHandle, final UpstreamWindowHookMutableSizePos hook) { final CapabilitiesImmutable caps = new Capabilities(); final AbstractGraphicsConfiguration config = new DefaultGraphicsConfiguration(aScreen, caps, caps); return new WrappedWindow(config, surfaceHandle, hook, true, windowHandle); } /** * @param nw * @return top-left client-area position in window units * <p> * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation * </p> */ public static PointImmutable getLocationOnScreen(final NativeWindow nw) { final String nwt = NativeWindowFactory.getNativeWindowType(true); if( NativeWindowFactory.TYPE_X11 == nwt ) { return X11Lib.GetRelativeLocation(nw.getDisplayHandle(), nw.getScreenIndex(), nw.getWindowHandle(), 0, 0, 0); } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { return GDIUtil.GetRelativeLocation(nw.getWindowHandle(), 0, 0, 0); } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { return OSXUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0); /** * FIXME: Needs service provider interface (SPI) for TK dependent implementation } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { } else if( NativeWindowFactory.TYPE_ANDROID== nwt ) { } else if( NativeWindowFactory.TYPE_EGL == nwt ) { } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { } else if( NativeWindowFactory.TYPE_AWT == nwt ) { */ } throw new UnsupportedOperationException("n/a for windowing system: "+nwt); } }