/* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. */ package jogamp.nativewindow.jawt; import java.awt.EventQueue; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Map; import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.AbstractGraphicsScreen; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.nativewindow.ToolkitLock; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; import jogamp.common.os.PlatformPropsImpl; import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.jawt.x11.X11SunJDKReflection; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.nativewindow.x11.X11Lib; import com.jogamp.common.os.Platform; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.VersionNumber; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; public class JAWTUtil { public static final boolean DEBUG = Debug.debug("JAWT"); private static final boolean SKIP_AWT_HIDPI; /** OSX JAWT version option to use CALayer */ public static final int JAWT_MACOSX_USE_CALAYER = 0x80000000; /** OSX JAWT CALayer availability on Mac OS X >= 10.6 Update 4 (recommended) */ public static final VersionNumber JAWT_MacOSXCALayerMinVersion = new VersionNumber(10,6,4); /** OSX JAWT CALayer required with Java >= 1.7.0 (implies OS X >= 10.7 */ public static final VersionNumber JAWT_MacOSXCALayerRequiredForJavaVersion = Platform.Version17; // 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; private static final boolean j2dExist; private static final Method sunToolkitAWTLockMethod; private static final Method sunToolkitAWTUnlockMethod; private static final boolean hasSunToolkitAWTLock; private static final RecursiveLock jawtLock; private static final ToolkitLock jawtToolkitLock; private static final Method getScaleFactorMethod; private static final Method getCGDisplayIDMethodOnOSX; private static class PrivilegedDataBlob1 { PrivilegedDataBlob1() { ok = false; } Method sunToolkitAWTLockMethod; Method sunToolkitAWTUnlockMethod; Method getScaleFactorMethod; Method getCGDisplayIDMethodOnOSX; boolean ok; } /** * Returns true if this platform's JAWT implementation supports offscreen layer. */ public static boolean isOffscreenLayerSupported() { return PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0; } /** * Returns true if this platform's JAWT implementation requires using offscreen layer. */ public static boolean isOffscreenLayerRequired() { return PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && PlatformPropsImpl.JAVA_VERSION_NUMBER.compareTo(JAWT_MacOSXCALayerRequiredForJavaVersion)>=0; } /** * CALayer size needs to be set using the AWT component size. * <p> * AWT's super-calayer, i.e. the AWT's own component CALayer, * does not layout our root-calayer in respect to this component's * position and size, at least when resizing programmatically. * </p> * <p> * As of today, this flag is enabled for all known AWT versions. * </p> * <p> * Sync w/ NativeWindowProtocols.h * </p> */ public static final int JAWT_OSX_CALAYER_QUIRK_SIZE = 1 << 0; /** * CALayer position needs to be set to zero. * <p> * AWT's super-calayer, i.e. the AWT's own component CALayer, * has a broken layout and needs it's sub-layers to be located at position 0/0. * </p> * <p> * See <code>http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172187</code>. * </p> * <p> * Further more a re-layout seems to be required in this case, * i.e. a programmatic forced resize +1 and it's inverted resize -1. * </p> * <p> * This flag is enabled w/ AWT < 1.7.0_40. * </p> * <p> * Sync w/ NativeWindowProtocols.h * </p> */ public static final int JAWT_OSX_CALAYER_QUIRK_POSITION = 1 << 1; /** * CALayer position needs to be derived from AWT position * in relation to super CALayer. * <p> * AWT's super-calayer, i.e. the AWT top-container's CALayer, * does not layout our root-calayer in respect to this component's * position and size, at least when resizing programmatically. * </p> * <p> * CALayer position has origin 0/0 at bottom/left, * where AWT component has origin 0/0 at top/left. * </p> * <p> * The super-calayer bounds exclude the frame's heavyweight border/insets. * </p> * <p> * The super-calayer lies within the AWT top-container client space (content). * </p> * <p> * Component's location in super-calayer: * <pre> p0 = c.locationOnScreen(); p0 -= c.getOutterComp.getPos(); p0 -= c.getOutterComp.getInsets(); * </pre> * Where 'locationOnScreen()' is: * <pre> p0 = 0/0; while( null != c ) { p0 += c.getPos(); } * </pre> * </p> * <p> * This flags also sets {@link #JAWT_OSX_CALAYER_QUIRK_SIZE}, * i.e. they are related. * </p> * <p> * As of today, this flag is enabled for w/ AWT >= 1.7.0_40. * </p> * <p> * Sync w/ NativeWindowProtocols.h * </p> */ public static final int JAWT_OSX_CALAYER_QUIRK_LAYOUT = 1 << 2; /** * Returns bitfield of required JAWT OSX CALayer quirks to mediate AWT impl. bugs. * <p> * Returns zero, if platform is not {@link Platform.OSType#MACOS} * or not supporting CALayer, i.e. OSX < 10.6.4. * </p> * <p> * Otherwise includes * <ul> * <li>{@link #JAWT_OSX_CALAYER_QUIRK_SIZE} (always)</li> * <li>{@link #JAWT_OSX_CALAYER_QUIRK_POSITION} if JVM < 1.7.0_40</li> * <li>{@link #JAWT_OSX_CALAYER_QUIRK_LAYOUT} if JVM >= 1.7.0_40</li> * </ul> * </p> */ public static int getOSXCALayerQuirks() { int res = 0; if( PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS && PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0 ) { /** Knowing impl. all expose the SIZE bug */ res |= JAWT_OSX_CALAYER_QUIRK_SIZE; final int c = PlatformPropsImpl.JAVA_VERSION_NUMBER.compareTo(PlatformPropsImpl.Version17); if( c < 0 || c == 0 && PlatformPropsImpl.JAVA_VERSION_UPDATE < 40 ) { res |= JAWT_OSX_CALAYER_QUIRK_POSITION; } else { res |= JAWT_OSX_CALAYER_QUIRK_LAYOUT; } } return res; } /** * @param useOffscreenLayerIfAvailable * @return */ public static JAWT getJAWT(final boolean useOffscreenLayerIfAvailable) { final int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; final JAWT jawt = JAWT.create(); // default queries boolean tryOffscreenLayer; boolean tryOnscreen; int jawt_version_flags_offscreen = jawt_version_flags; if(isOffscreenLayerRequired()) { if(PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) { if(PlatformPropsImpl.OS_VERSION_NUMBER.compareTo(JAWTUtil.JAWT_MacOSXCALayerMinVersion) >= 0) { jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER; tryOffscreenLayer = true; tryOnscreen = false; } else { throw new RuntimeException("OSX: Invalid version of Java ("+PlatformPropsImpl.JAVA_VERSION_NUMBER+") / OS X ("+PlatformPropsImpl.OS_VERSION_NUMBER+")"); } } else { throw new InternalError("offscreen required, but n/a for: "+PlatformPropsImpl.OS_TYPE); } } else if(useOffscreenLayerIfAvailable && isOffscreenLayerSupported()) { if(PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) { jawt_version_flags_offscreen |= JAWTUtil.JAWT_MACOSX_USE_CALAYER; tryOffscreenLayer = true; tryOnscreen = true; } else { throw new InternalError("offscreen requested and supported, but n/a for: "+PlatformPropsImpl.OS_TYPE); } } else { tryOffscreenLayer = false; tryOnscreen = true; } if(DEBUG) { System.err.println("JAWTUtil.getJAWT(tryOffscreenLayer "+tryOffscreenLayer+", tryOnscreen "+tryOnscreen+")"); } final StringBuilder errsb = new StringBuilder(); if(tryOffscreenLayer) { errsb.append("Offscreen 0x").append(Integer.toHexString(jawt_version_flags_offscreen)); if( JAWT.getJAWT(jawt, jawt_version_flags_offscreen) ) { return jawt; } } if(tryOnscreen) { if(tryOffscreenLayer) { errsb.append(", "); } errsb.append("Onscreen 0x").append(Integer.toHexString(jawt_version_flags)); if( JAWT.getJAWT(jawt, jawt_version_flags) ) { return jawt; } } throw new RuntimeException("Unable to initialize JAWT, trials: "+errsb.toString()); } public static boolean isJAWTUsingOffscreenLayer(final JAWT jawt) { return 0 != ( jawt.getCachedVersion() & JAWTUtil.JAWT_MACOSX_USE_CALAYER ); } static { SKIP_AWT_HIDPI = PropertyAccess.isPropertyDefined("nativewindow.awt.nohidpi", true); if(DEBUG) { System.err.println("JAWTUtil initialization (JAWT/JNI/...); SKIP_AWT_HIDPI "+SKIP_AWT_HIDPI); // Thread.dumpStack(); } headlessMode = GraphicsEnvironment.isHeadless(); if( headlessMode ) { // Headless case jawtLockObject = null; isQueueFlusherThread = null; j2dExist = false; sunToolkitAWTLockMethod = null; sunToolkitAWTUnlockMethod = null; hasSunToolkitAWTLock = false; // hasSunToolkitAWTLock = false; getScaleFactorMethod = null; getCGDisplayIDMethodOnOSX = null; } else { // Non-headless case JAWTJNILibLoader.initSingleton(); // load libjawt.so if(!NWJNILibLoader.loadNativeWindow("awt")) { // load libnativewindow_awt.so throw new NativeWindowException("NativeWindow AWT native library load error."); } jawtLockObject = getJAWT(false); // don't care for offscreen layer here boolean j2dExistTmp = false; Class<?> java2DClass = null; Method isQueueFlusherThreadTmp = null; try { java2DClass = Class.forName("jogamp.opengl.awt.Java2D"); isQueueFlusherThreadTmp = java2DClass.getMethod("isQueueFlusherThread", (Class[])null); j2dExistTmp = true; } catch (final Exception e) { } isQueueFlusherThread = isQueueFlusherThreadTmp; j2dExist = j2dExistTmp; final PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { final PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); try { final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); d.sunToolkitAWTLockMethod.setAccessible(true); d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); d.sunToolkitAWTUnlockMethod.setAccessible(true); d.ok=true; } catch (final Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } try { final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); final Class<?> gdClass = gd.getClass(); d.getScaleFactorMethod = gdClass.getDeclaredMethod("getScaleFactor"); d.getScaleFactorMethod.setAccessible(true); if( Platform.OSType.MACOS == PlatformPropsImpl.OS_TYPE ) { d.getCGDisplayIDMethodOnOSX = gdClass.getDeclaredMethod("getCGDisplayID"); d.getCGDisplayIDMethodOnOSX.setAccessible(true); } } catch (final Throwable t) {} return d; } }); sunToolkitAWTLockMethod = pdb1.sunToolkitAWTLockMethod; sunToolkitAWTUnlockMethod = pdb1.sunToolkitAWTUnlockMethod; getScaleFactorMethod = pdb1.getScaleFactorMethod; getCGDisplayIDMethodOnOSX = pdb1.getCGDisplayIDMethodOnOSX; boolean _hasSunToolkitAWTLock = false; if ( pdb1.ok ) { try { sunToolkitAWTLockMethod.invoke(null, (Object[])null); sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); _hasSunToolkitAWTLock = true; } catch (final Exception e) { } } hasSunToolkitAWTLock = _hasSunToolkitAWTLock; // hasSunToolkitAWTLock = false; } jawtLock = LockFactory.createRecursiveLock(); jawtToolkitLock = new ToolkitLock() { @Override public final void lock() { JAWTUtil.lockToolkit(); } @Override public final void unlock() { JAWTUtil.unlockToolkit(); } @Override public final void validateLocked() throws RuntimeException { JAWTUtil.validateLocked(); } @Override public final void dispose() { // nop } @Override public String toString() { return "JAWTToolkitLock[obj 0x"+Integer.toHexString(hashCode())+", isOwner "+jawtLock.isOwner(Thread.currentThread())+", "+jawtLock+"]"; } }; // trigger native AWT toolkit / properties initialization Map<?,?> desktophints = null; try { if(EventQueue.isDispatchThread()) { desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); } else { final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1); EventQueue.invokeAndWait(new Runnable() { @Override public void run() { final Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if(null!=_desktophints) { desktophintsBucket.add(_desktophints); } } }); desktophints = ( desktophintsBucket.size() > 0 ) ? desktophintsBucket.get(0) : null ; } } catch (final InterruptedException ex) { ex.printStackTrace(); } catch (final InvocationTargetException ex) { ex.printStackTrace(); } if (DEBUG) { System.err.println("JAWTUtil: Has sun.awt.SunToolkit.awtLock/awtUnlock " + hasSunToolkitAWTLock); System.err.println("JAWTUtil: Has Java2D " + j2dExist); System.err.println("JAWTUtil: Is headless " + headlessMode); final int hints = ( null != desktophints ) ? desktophints.size() : 0 ; System.err.println("JAWTUtil: AWT Desktop hints " + hints); System.err.println("JAWTUtil: OffscreenLayer Supported: "+isOffscreenLayerSupported()+" - Required "+isOffscreenLayerRequired()); } } /** * Called by {@link NativeWindowFactory#initSingleton()} */ public static void initSingleton() { // just exist to ensure static init has been run } /** * Called by {@link NativeWindowFactory#shutdown()} */ public static void shutdown() { } public static boolean hasJava2D() { return j2dExist; } public static boolean isJava2DQueueFlusherThread() { boolean b = false; if(j2dExist) { try { b = ((Boolean)isQueueFlusherThread.invoke(null, (Object[])null)).booleanValue(); } catch (final Exception e) {} } return b; } public static boolean isHeadlessMode() { return headlessMode; } /** * Locks the AWT's global ReentrantLock. * <p> * JAWT's native Lock() function calls SunToolkit.awtLock(), * which just uses AWT's global ReentrantLock. * </p> * <p> * AWT locking is wrapped through a recursive lock object. * </p> */ public static void lockToolkit() throws NativeWindowException { jawtLock.lock(); if( 1 == jawtLock.getHoldCount() ) { if(!headlessMode && !isJava2DQueueFlusherThread()) { if(hasSunToolkitAWTLock) { try { sunToolkitAWTLockMethod.invoke(null, (Object[])null); } catch (final Exception e) { throw new NativeWindowException("SunToolkit.awtLock failed", e); } } else { jawtLockObject.Lock(); } } } if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.lock(): "+jawtLock); } } /** * Unlocks the AWT's global ReentrantLock. * <p> * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), * which just uses AWT's global ReentrantLock. * </p> * <p> * AWT unlocking is wrapped through a recursive lock object. * </p> */ public static void unlockToolkit() { jawtLock.validateLocked(); if(ToolkitLock.TRACE_LOCK) { System.err.println("JAWTUtil-ToolkitLock.unlock(): "+jawtLock); } if( 1 == jawtLock.getHoldCount() ) { if(!headlessMode && !isJava2DQueueFlusherThread()) { if(hasSunToolkitAWTLock) { try { sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); } catch (final Exception e) { throw new NativeWindowException("SunToolkit.awtUnlock failed", e); } } else { jawtLockObject.Unlock(); } } } jawtLock.unlock(); } public static final void validateLocked() throws RuntimeException { jawtLock.validateLocked(); } public static ToolkitLock getJAWTToolkitLock() { return jawtToolkitLock; } public static final int getMonitorDisplayID(final GraphicsDevice device) { int displayID = 0; if( null != getCGDisplayIDMethodOnOSX ) { // OSX specific try { final Object res = getCGDisplayIDMethodOnOSX.invoke(device); if (res instanceof Integer) { displayID = ((Integer)res).intValue(); } } catch (final Throwable t) {} } return displayID; } /** * Returns the pixel scale factor of the given {@link GraphicsDevice}, if supported. * <p> * If the component does not support pixel scaling the default * <code>one</code> is returned. * </p> * <p> * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays * </p> * @param device the {@link GraphicsDevice} instance used to query the pixel scale * @param minScale current and output min scale values * @param maxScale current and output max scale values * @return {@code true} if the given min and max scale values have changed, otherwise {@code false}. */ public static final boolean getPixelScale(final GraphicsDevice device, final float[] minScale, final float[] maxScale) { // Shall we allow ]0..1[ minimum scale? boolean changed = minScale[0] != 1f || minScale[1] != 1f; minScale[0] = 1f; minScale[1] = 1f; float sx = 1f; float sy = 1f; if( !SKIP_AWT_HIDPI ) { if( null != getCGDisplayIDMethodOnOSX ) { // OSX specific, preserving double type try { final Object res = getCGDisplayIDMethodOnOSX.invoke(device); if (res instanceof Integer) { final int displayID = ((Integer)res).intValue(); sx = (float) OSXUtil.GetPixelScaleByDisplayID(displayID); sy = sx; } } catch (final Throwable t) {} } if( null != getScaleFactorMethod ) { // Generic (?) try { final Object res = getScaleFactorMethod.invoke(device); if (res instanceof Integer) { sx = ((Integer)res).floatValue(); } else if ( res instanceof Double) { sx = ((Double)res).floatValue(); } sy = sx; } catch (final Throwable t) {} } } changed = maxScale[0] != sx || maxScale[1] != sy; maxScale[0] = sx; maxScale[1] = sy; return changed; } /** * Returns the pixel scale factor of the given {@link GraphicsConfiguration}'s {@link GraphicsDevice}, if supported. * <p> * If the {@link GraphicsDevice} is <code>null</code>, <code>zero</code> is returned. * </p> * <p> * If the component does not support pixel scaling the default * <code>one</code> is returned. * </p> * <p> * Note: Currently only supported on OSX since 1.7.0_40 for HiDPI retina displays * </p> * @param gc the {@link GraphicsConfiguration} instance used to query the pixel scale * @param minScale current and output min scale values * @param maxScale current and output max scale values * @return {@code true} if the given min and max scale values have changed, otherwise {@code false}. */ public static final boolean getPixelScale(final GraphicsConfiguration gc, final float[] minScale, final float[] maxScale) { final GraphicsDevice device = null != gc ? gc.getDevice() : null; boolean changed; if( null == device ) { changed = minScale[0] != 1f || minScale[1] != 1f || maxScale[0] != 1f || maxScale[1] != 1f; minScale[0] = 1f; minScale[1] = 1f; maxScale[0] = 1f; maxScale[1] = 1f; } else { changed = JAWTUtil.getPixelScale(device, minScale, maxScale); } return changed; } private static String getThreadName() { return Thread.currentThread().getName(); } private static String toHexString(final long val) { return "0x" + Long.toHexString(val); } /** * @param awtComp must be {@link java.awt.Component#isDisplayable() displayable} * and must have a {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration} * @return AbstractGraphicsDevice instance reflecting the {@code awtComp} * @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable} * or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}. * @see #getAbstractGraphicsScreen(java.awt.Component) */ public static AbstractGraphicsDevice createDevice(final java.awt.Component awtComp) throws IllegalArgumentException { if( !awtComp.isDisplayable() ) { throw new IllegalArgumentException("Given AWT-Component is not displayable: "+awtComp); } final GraphicsDevice device; final GraphicsConfiguration gc = awtComp.getGraphicsConfiguration(); if(null!=gc) { device = gc.getDevice(); } else { throw new IllegalArgumentException("Given AWT-Component has no GraphicsConfiguration set: "+awtComp); } final String displayConnection; final String nwt = NativeWindowFactory.getNativeWindowType(true); if( NativeWindowFactory.TYPE_X11 == nwt ) { final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); if( 0 == displayHandleAWT ) { displayConnection = null; // default if(DEBUG) { System.err.println(getThreadName()+" - JAWTUtil.createDevice: Null AWT dpy, default 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. */ displayConnection = X11Lib.XDisplayString(displayHandleAWT); if(DEBUG) { System.err.println(getThreadName()+" - JAWTUtil.createDevice: AWT dpy "+displayConnection+" / "+toHexString(displayHandleAWT)); } } } else { displayConnection = null; // default } return NativeWindowFactory.createDevice(displayConnection, true /* own */); } /** * @param awtComp must be {@link java.awt.Component#isDisplayable() displayable} * and must have a {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration} * @return AbstractGraphicsScreen instance reflecting the {@code awtComp} * @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable} * or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}. * @see #createDevice(java.awt.Component) */ public static AbstractGraphicsScreen getAbstractGraphicsScreen(final java.awt.Component awtComp) throws IllegalArgumentException { final AbstractGraphicsDevice adevice = createDevice(awtComp); return NativeWindowFactory.createScreen(adevice, AWTGraphicsScreen.findScreenIndex(awtComp.getGraphicsConfiguration().getDevice())); } }