diff options
153 files changed, 4741 insertions, 1648 deletions
diff --git a/make/build-jogl.xml b/make/build-jogl.xml index 58e018024..511f147be 100644 --- a/make/build-jogl.xml +++ b/make/build-jogl.xml @@ -1130,6 +1130,8 @@ <linker id="linker.cfg.macosx.jogl" extends="linker.cfg.macosx"> <linkerarg value="-framework" /> + <linkerarg value="QuartzCore" /> + <linkerarg value="-framework" /> <linkerarg value="Cocoa" /> <linkerarg value="-framework" /> <linkerarg value="OpenGL" /> @@ -1276,8 +1278,10 @@ <patternset id="c.src.files.jogl.desktop"> <include name="${rootrel.src.c}/JoglCommon.c"/> <include name="${rootrel.src.c}/GLDebugMessageHandler.c"/> + <include name="${rootrel.src.c}/timespec.c" if="isOSX"/> <!-- currently only used for OSX --> <include name="${rootrel.src.c}/macosx/MacOSXCustomCGLCode.c" if="isOSX"/> <include name="${rootrel.src.c}/macosx/MacOSXWindowSystemInterface.m" if="isOSX"/> + <include name="${rootrel.src.c}/macosx/MacOSXWindowSystemInterface-pbuffer.m" if="isOSX"/> <include name="${rootrel.src.c}/macosx/ContextUpdater.m" if="isOSX"/> <include name="${rootrel.src.c}/GLXGetProcAddressARB.c" if="isX11"/> <!-- FIXME: the Mixer should be moved to another library --> @@ -1349,6 +1353,7 @@ <includepath path="stub_includes/cg" if="setup.addNativeNVidiaCG"/> <!-- This is for the generated headers for handwritten C code --> + <includepath path="${src.c}"/> <includepath path="${src.generated.c}" /> <includepath path="${src.generated.c}/X11" if="isX11"/> <includepath path="${src.generated.c}/MacOSX" if="isOSX"/> diff --git a/make/build-nativewindow.xml b/make/build-nativewindow.xml index 4bbe667b8..9d0dff406 100644 --- a/make/build-nativewindow.xml +++ b/make/build-nativewindow.xml @@ -354,6 +354,10 @@ <compilerarg value="-I/usr/X11R6/include" /> </compiler> + <compiler id="compiler.cfg.macosx.nativewindow" extends="compiler.cfg.macosx"> + <compilerarg value="-I${java.osx.frameworks.dir}/JavaNativeFoundation.framework/Headers" /> + </compiler> + <!-- linker configuration --> <linker id="linker.cfg.freebsd.nativewindow.x11" extends="linker.cfg.freebsd"> @@ -443,7 +447,13 @@ <linker id="linker.cfg.macosx.nativewindow" extends="linker.cfg.macosx"> <linkerarg value="-framework" /> + <linkerarg value="QuartzCore" /> + <linkerarg value="-framework" /> <linkerarg value="Cocoa" /> + <linkerarg value="-framework" /> + <linkerarg value="JavaNativeFoundation" /> + <linkerarg value="-F" /> + <linkerarg value="${java.osx.frameworks.dir}" /> </linker> <linker id="linker.cfg.hpux.nativewindow" extends="linker.cfg.hpux"> @@ -547,7 +557,7 @@ <target name="c.configure.x11" if="isX11" /> <target name="c.configure.macosx" if="isOSX"> - <property name="compiler.cfg.id" value="compiler.cfg.macosx" /> + <property name="compiler.cfg.id" value="compiler.cfg.macosx.nativewindow" /> <property name="linker.cfg.id.oswin" value="linker.cfg.macosx.nativewindow" /> </target> @@ -734,6 +744,7 @@ <target name="c.build.nativewindow.windowlib.macosx" if="isOSX"> <javah destdir="${src.generated.c}/MacOSX" classpath="${javah.classpath}" class="jogamp.nativewindow.macosx.OSXUtil" /> + <javah destdir="${src.generated.c}/MacOSX" classpath="${javah.classpath}" class="jogamp.nativewindow.jawt.macosx.MacOSXJAWTWindow" /> <c.build c.compiler.src.files="c.src.files.macosx" output.lib.name="nativewindow_macosx" diff --git a/make/build-newt.xml b/make/build-newt.xml index d3248fa9d..56ebfaccc 100644 --- a/make/build-newt.xml +++ b/make/build-newt.xml @@ -96,7 +96,7 @@ <!-- partitioning --> <property name="java.part.core" - value="com/jogamp/newt/* com/jogamp/newt/event/* com/jogamp/newt/util/* jogamp/newt/* jogamp/newt/event/*"/> + value="com/jogamp/newt/* com/jogamp/newt/event/* com/jogamp/newt/util/* jogamp/newt/* jogamp/newt/event/* jogamp/newt/driver/*"/> <property name="java.part.opengl" value="com/jogamp/newt/opengl/**"/> diff --git a/make/config/jogl/cgl-macosx.cfg b/make/config/jogl/cgl-macosx.cfg index 06bc94626..7d17c4aff 100644 --- a/make/config/jogl/cgl-macosx.cfg +++ b/make/config/jogl/cgl-macosx.cfg @@ -20,6 +20,13 @@ Opaque long CGLShareGroupObj Opaque long CGLPBufferObj Opaque long CGLPixelFormatObj +Opaque long NSOpenGLPixelFormat * +Opaque long NSOpenGLContext * +Opaque long NSView * +Opaque long NSOpenGLView * +Opaque long NSOpenGLPixelBuffer * +Opaque long NSOpenGLLayer * + CustomCCode #include </usr/include/machine/types.h> CustomCCode #include "macosx-window-system.h" diff --git a/make/config/jogl/gl-impl-CustomJavaCode-common.java b/make/config/jogl/gl-impl-CustomJavaCode-common.java index 0a8e90171..0878bd236 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-common.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-common.java @@ -35,6 +35,11 @@ return _context.isExtensionAvailable(glExtensionName); } + public boolean isNPOTTextureAvailable() { + return isGL3() || isGLES2() || isExtensionAvailable(GL_ARB_texture_non_power_of_two); + } + private static final String GL_ARB_texture_non_power_of_two = "GL_ARB_texture_non_power_of_two"; + public Object getExtension(String extensionName) { // At this point we don't expose any extensions using this mechanism return null; diff --git a/make/config/nativewindow/jawt-CustomJavaCode.java b/make/config/nativewindow/jawt-CustomJavaCode.java index 3223a74b1..d3dc3845f 100644 --- a/make/config/nativewindow/jawt-CustomJavaCode.java +++ b/make/config/nativewindow/jawt-CustomJavaCode.java @@ -1,27 +1,38 @@ -private static volatile JAWT jawt; +/** Available and recommended on Mac OS X >= 10.6 Update 4 */ +public static final int JAWT_MACOSX_USE_CALAYER = 0x80000000; +public static final VersionNumber JAWT_MacOSXCALayerMinVersion = new VersionNumber(10,6,4); + +private int jawt_version_cached = 0; + +public final int getCachedVersion() { + return jawt_version_cached; +} /** Helper routine for all users to call to access the JAWT. */ -public static JAWT getJAWT() { - if (jawt == null) { - synchronized (JAWT.class) { - if (jawt == null) { - JAWTUtil.initSingleton(); - // Workaround for 4845371. - // Make sure the first reference to the JNI GetDirectBufferAddress is done - // from a privileged context so the VM's internal class lookups will succeed. - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - JAWT j = JAWT.create(); - j.setVersion(JAWTFactory.JAWT_VERSION_1_4); - if (!JAWTFactory.JAWT_GetAWT(j)) { - throw new RuntimeException("Unable to initialize JAWT"); +public static JAWT getJAWT(final int jawt_version_flags) { + JAWTUtil.initSingleton(); + // Workaround for 4845371. + // Make sure the first reference to the JNI GetDirectBufferAddress is done + // from a privileged context so the VM's internal class lookups will succeed. + return AccessController.doPrivileged(new PrivilegedAction<JAWT>() { + public JAWT run() { + int jawt_version_flags_mod = jawt_version_flags; + JAWT jawt = JAWT.create(); + if( 0 != ( jawt_version_flags_mod & JAWT_MACOSX_USE_CALAYER ) ) { + jawt.setVersion(jawt_version_flags_mod); + if (JAWTFactory.JAWT_GetAWT(jawt)) { + jawt.jawt_version_cached = jawt.getVersion(); + return jawt; } - jawt = j; - return null; - } - }); - } - } - } - return jawt; + jawt_version_flags_mod &= ~JAWT_MACOSX_USE_CALAYER; + System.err.println("MacOSX "+Platform.OS_VERSION_NUMBER+" >= "+JAWT_MacOSXCALayerMinVersion+": Failed to use JAWT_MACOSX_USE_CALAYER"); + } + jawt.setVersion(jawt_version_flags_mod); + if (!JAWTFactory.JAWT_GetAWT(jawt)) { + throw new RuntimeException("Unable to initialize JAWT: 0x"+Integer.toHexString(jawt_version_flags_mod)); + } + jawt.jawt_version_cached = jawt.getVersion(); + return jawt; + } + }); } diff --git a/make/config/nativewindow/jawt-DrawingSurfaceInfo-CustomJavaCode.java b/make/config/nativewindow/jawt-DrawingSurfaceInfo-CustomJavaCode.java index 598ced346..4ff3a45b0 100644 --- a/make/config/nativewindow/jawt-DrawingSurfaceInfo-CustomJavaCode.java +++ b/make/config/nativewindow/jawt-DrawingSurfaceInfo-CustomJavaCode.java @@ -1,30 +1,29 @@ -public JAWT_PlatformInfo platformInfo() { - return newPlatformInfo(platformInfo0(getBuffer())); +public JAWT_PlatformInfo platformInfo(final JAWT jawt) { + return newPlatformInfo(jawt, platformInfo0(getBuffer())); } private native ByteBuffer platformInfo0(Buffer jthis0); private static java.lang.reflect.Method platformInfoFactoryMethod; -private static JAWT_PlatformInfo newPlatformInfo(ByteBuffer buf) { +private static JAWT_PlatformInfo newPlatformInfo(JAWT jawt, ByteBuffer buf) { if (platformInfoFactoryMethod == null) { - String osName = (String) AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return System.getProperty("os.name").toLowerCase(); - } - }); try { - Class factoryClass; - if (osName.startsWith("wind")) { - factoryClass = Class.forName("jogamp.nativewindow.jawt.windows.JAWT_Win32DrawingSurfaceInfo"); - } else if (osName.startsWith("mac os x")) { - factoryClass = Class.forName("jogamp.nativewindow.jawt.macosx.JAWT_MacOSXDrawingSurfaceInfo"); - } else { - // Assume Linux, Solaris, etc. Should probably test for these explicitly. - factoryClass = Class.forName("jogamp.nativewindow.jawt.x11.JAWT_X11DrawingSurfaceInfo"); - } - platformInfoFactoryMethod = factoryClass.getMethod("create", - new Class[] { ByteBuffer.class }); + Class<?> factoryClass; + if (Platform.OS_TYPE == Platform.OSType.WINDOWS) { + factoryClass = Class.forName("jogamp.nativewindow.jawt.windows.JAWT_Win32DrawingSurfaceInfo"); + } else if (Platform.OS_TYPE == Platform.OSType.MACOS) { + if( 0 != ( jawt.getCachedVersion() & JAWT.JAWT_MACOSX_USE_CALAYER ) ) { + factoryClass = Class.forName("jogamp.nativewindow.jawt.macosx.JAWT_SurfaceLayers"); + } else { + factoryClass = Class.forName("jogamp.nativewindow.jawt.macosx.JAWT_MacOSXDrawingSurfaceInfo"); + } + } else { + // Assume Linux, Solaris, etc. Should probably test for these explicitly. + factoryClass = Class.forName("jogamp.nativewindow.jawt.x11.JAWT_X11DrawingSurfaceInfo"); + } + platformInfoFactoryMethod = factoryClass.getMethod("create", + new Class[] { ByteBuffer.class }); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/make/config/nativewindow/jawt-common.cfg b/make/config/nativewindow/jawt-common.cfg index d633c47d6..55f3f368b 100644 --- a/make/config/nativewindow/jawt-common.cfg +++ b/make/config/nativewindow/jawt-common.cfg @@ -22,5 +22,7 @@ CustomCCode #include <jawt.h> import java.security.* import jogamp.nativewindow.jawt.* +import com.jogamp.common.os.Platform +import com.jogamp.common.util.VersionNumber IncludeAs CustomJavaCode JAWT_DrawingSurfaceInfo jawt-DrawingSurfaceInfo-CustomJavaCode.java diff --git a/make/config/nativewindow/jawt-macosx.cfg b/make/config/nativewindow/jawt-macosx.cfg index c41367f4a..20260f693 100644 --- a/make/config/nativewindow/jawt-macosx.cfg +++ b/make/config/nativewindow/jawt-macosx.cfg @@ -5,6 +5,7 @@ NativeOutputDir gensrc/native/MacOSX Opaque long void * Opaque long NSView * +Opaque long CALayer * CustomCCode #include <inttypes.h> CustomCCode #include </usr/include/machine/types.h> @@ -12,3 +13,7 @@ CustomCCode #include </usr/include/machine/types.h> StructPackage JAWT_MacOSXDrawingSurfaceInfo jogamp.nativewindow.jawt.macosx EmitStruct JAWT_MacOSXDrawingSurfaceInfo Implements JAWT_MacOSXDrawingSurfaceInfo JAWT_PlatformInfo + +StructPackage JAWT_SurfaceLayers jogamp.nativewindow.jawt.macosx +EmitStruct JAWT_SurfaceLayers +Implements JAWT_SurfaceLayers JAWT_PlatformInfo diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat index b45b49e89..d8bf861e0 100755 --- a/make/scripts/tests-x64.bat +++ b/make/scripts/tests-x64.bat @@ -12,7 +12,7 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLPro REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper %1 %2 %3 %4 %5 %6 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNEWT -time 30000 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es1.newt.TestGearsES1NEWT %1 %2 %3 -scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %1 %2 %3 %4 %5 %6 +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %1 %2 %3 %4 %5 %6 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT -time 5000 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWT -time 5000 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.awt.TestAWT03GLCanvasRecreate01 @@ -30,10 +30,12 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestWindows01NE REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestGLWindows02NEWTAnimated REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT -REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestFocus02SwingAWTRobot REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestFocus01SwingAWTRobot %1 %2 %3 %4 %5 %6 +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestFocus02SwingAWTRobot %1 %2 %3 %4 %5 %6 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.nativewindow.TestRecursiveToolkitLockCORE REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting03AWT -time 100000 +scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParentingFocusTraversal01AWT %1 %2 %3 +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer01AWT %1 %2 %3 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting03bAWT -time 100000 REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.TestFocus02SwingAWTRobot diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index cbea43cc9..4fc859829 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -49,7 +49,7 @@ function jrun() { shift #D_ARGS="-Djogl.debug.ExtensionAvailabilityCache -Djogl.debug=all -Dnativewindow.debug=all -Djogamp.debug.ProcAddressHelper=true -Djogamp.debug.NativeLibrary=true -Djogamp.debug.NativeLibrary.Lookup=true" - D_ARGS="-Dnativewindow.debug=all" + #D_ARGS="-Dnativewindow.debug=all -Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnewt.debug.Window" #D_ARGS="-Djogl.debug=all -Dnativewindow.debug=all" #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.ExtensionAvailabilityCache" #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile -Djogl.debug.GLDrawable" @@ -75,7 +75,7 @@ function jrun() { #D_ARGS="-Djogl.debug=all -Dnewt.debug=all" #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT -Djogl.debug.GLContext" #D_ARGS="-Dnewt.debug.Window -Djogl.debug.Animator -Dnewt.debug.Screen" - #D_ARGS="-Dnewt.debug.Window" + D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Window.KeyEvent" #D_ARGS="-Dnewt.debug.Window.MouseEvent" #D_ARGS="-Xprof" #D_ARGS="-Djogl.debug.Animator" @@ -223,13 +223,16 @@ function testswt() { #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper #testawt com.jogamp.opengl.test.junit.newt.TestEventSourceNotAWTBug #testawt com.jogamp.opengl.test.junit.newt.TestFocus01SwingAWTRobot $* -#testawt com.jogamp.opengl.test.junit.newt.TestFocus02SwingAWTRobot +#testawt com.jogamp.opengl.test.junit.newt.TestFocus02SwingAWTRobot $* #testawt com.jogamp.opengl.test.junit.newt.TestListenerCom01AWT #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01aAWT $* #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01bAWT $* #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01cAWT $* #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01cSwingAWT $* -testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting03AWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting02AWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting03AWT $* +testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingFocusTraversal01AWT $* +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer01AWT $* #testawt com.jogamp.opengl.test.junit.newt.parenting.TestTranslucentParentingAWT $* #testawt com.jogamp.opengl.test.junit.newt.TestCloseNewtAWT #testawt com.jogamp.opengl.test.junit.jogl.caps.TestMultisampleAWT $* @@ -273,6 +276,7 @@ testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting03AWT $* # # regressions # +#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParentingOffscreenLayer01AWT $* $spath/count-edt-start.sh java-run.log diff --git a/make/stub_includes/jni/macosx/jawt_md.h b/make/stub_includes/jni/macosx/jawt_md.h index aca47f66e..3a371af0d 100644 --- a/make/stub_includes/jni/macosx/jawt_md.h +++ b/make/stub_includes/jni/macosx/jawt_md.h @@ -9,17 +9,35 @@ #include <jawt.h> #include <AppKit/NSView.h> +#include <QuartzCore/CALayer.h> #ifdef __cplusplus extern "C" { #endif +/** + * JAWT_DrawingSurfaceInfo.getPlatformInfo() + * + * Only if not JAWT_SurfaceLayers, see below! + */ typedef struct JAWT_MacOSXDrawingSurfaceInfo { - NSView *cocoaViewRef; // the view is guaranteed to be valid only for the duration of Component.paint method + /** the view is guaranteed to be valid only for the duration of Component.paint method */ + NSView *cocoaViewRef; } JAWT_MacOSXDrawingSurfaceInfo; +/** + * JAWT_DrawingSurfaceInfo.getPlatformInfo() + * + * >= 10.6.4 if JAWT_MACOSX_USE_CALAYER is set in JAWT version + */ +typedef struct JAWT_SurfaceLayers +{ + CALayer *layer; +} +JAWT_SurfaceLayers; + #ifdef __cplusplus } #endif diff --git a/make/stub_includes/macosx/AppKit/NSOpenGL.h b/make/stub_includes/macosx/AppKit/NSOpenGL.h new file mode 100644 index 000000000..1b7656dc1 --- /dev/null +++ b/make/stub_includes/macosx/AppKit/NSOpenGL.h @@ -0,0 +1,3 @@ +typedef struct _NSOpenGLPixelFormat NSOpenGLPixelFormat; +typedef struct _NSOpenGLContext NSOpenGLContext; +typedef struct _NSOpenGLPixelBuffer NSOpenGLPixelBuffer; diff --git a/make/stub_includes/macosx/AppKit/NSOpenGLLayer.h b/make/stub_includes/macosx/AppKit/NSOpenGLLayer.h new file mode 100644 index 000000000..2e5e81a68 --- /dev/null +++ b/make/stub_includes/macosx/AppKit/NSOpenGLLayer.h @@ -0,0 +1 @@ +typedef struct _NSOpenGLLayer NSOpenGLLayer; diff --git a/make/stub_includes/macosx/AppKit/NSOpenGLView.h b/make/stub_includes/macosx/AppKit/NSOpenGLView.h new file mode 100644 index 000000000..6492287df --- /dev/null +++ b/make/stub_includes/macosx/AppKit/NSOpenGLView.h @@ -0,0 +1 @@ +typedef struct _NSOpenGLView NSOpenGLView; diff --git a/make/stub_includes/macosx/OpenGL/CGLDevice.h b/make/stub_includes/macosx/OpenGL/CGLDevice.h new file mode 100644 index 000000000..1d4170975 --- /dev/null +++ b/make/stub_includes/macosx/OpenGL/CGLDevice.h @@ -0,0 +1,2 @@ +typedef struct _cglShareGroupObj* CGLShareGroupObj; + diff --git a/make/stub_includes/macosx/OpenGL/OpenGL.h b/make/stub_includes/macosx/OpenGL/OpenGL.h index 1a3ddf203..33cfa46b6 100644 --- a/make/stub_includes/macosx/OpenGL/OpenGL.h +++ b/make/stub_includes/macosx/OpenGL/OpenGL.h @@ -2,10 +2,13 @@ OpenGL.h to expose portions of the low-level CGL API to Java */ /* Typedefs to get things working */ -typedef struct _cglObj* CGLContextObj; -typedef struct _cglObj* CGLShareGroupObj; -typedef struct _cglObj* CGLPBufferObj; -typedef struct _cglObj* CGLPixelFormatObj; +typedef struct _cglContextObj* CGLContextObj; +typedef struct _cglPBufferObj* CGLPBufferObj; +typedef struct _cglPixelFormatObj* CGLPixelFormatObj; + +typedef int GLint; /* 4-byte signed */ +typedef unsigned int GLenum; +typedef int GLsizei; /* 4-byte signed */ /* ** Attribute names for CGLChoosePixelFormat and CGLDescribePixelFormat. @@ -105,7 +108,7 @@ typedef enum _CGLContextParameter { /* Pixel format manipulation */ CGLError CGLChoosePixelFormat(const CGLPixelFormatAttribute *attribs, CGLPixelFormatObj *pix, - long *npix); + GLint *npix); CGLError CGLDestroyPixelFormat(CGLPixelFormatObj pix); CGLPixelFormatObj CGLGetPixelFormat ( CGLContextObj ctx ); @@ -123,16 +126,16 @@ CGLError CGLCopyContext ( CGLContextObj src, CGLContextObj dst, int mask ); CGLShareGroupObj CGLGetShareGroup(CGLContextObj ctx); -/* PBuffer manipulation */ -CGLError CGLCreatePBuffer(long width, - long height, - unsigned long target, - unsigned long internalFormat, - long max_level, +/* PBuffer manipulation (deprecated in 10.7) */ +CGLError CGLCreatePBuffer(GLsizei width, + GLsizei height, + GLenum target, + GLenum internalFormat, + GLint max_level, CGLPBufferObj* pbuffer); CGLError CGLDestroyPBuffer(CGLPBufferObj pbuffer); CGLError CGLSetPBuffer(CGLContextObj ctx, CGLPBufferObj pbuffer, - unsigned long face, - long level, - long screen); + GLenum face, + GLint level, + GLint screen); diff --git a/make/stub_includes/macosx/QuartzCore/CALayer.h b/make/stub_includes/macosx/QuartzCore/CALayer.h new file mode 100644 index 000000000..a5a6579a6 --- /dev/null +++ b/make/stub_includes/macosx/QuartzCore/CALayer.h @@ -0,0 +1 @@ +typedef struct _CALayer CALayer; diff --git a/make/stub_includes/opengl/macosx-window-system.h b/make/stub_includes/opengl/macosx-window-system.h index 65d8e41f7..347de6299 100644 --- a/make/stub_includes/opengl/macosx-window-system.h +++ b/make/stub_includes/opengl/macosx-window-system.h @@ -7,55 +7,63 @@ compilation then the build fails. */ +#include <AppKit/NSView.h> +#include <AppKit/NSOpenGL.h> +#include <AppKit/NSOpenGLView.h> +#include <AppKit/NSOpenGLLayer.h> +#include <OpenGL/CGLDevice.h> +#include <OpenGL/OpenGL.h> + typedef int Bool; // CGL .. -void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues); +void CGLQueryPixelFormat(CGLPixelFormatObj fmt, int* iattrs, int niattrs, int* ivalues); // NS .. -void* createPixelFormat(int* iattrs, int niattrs, int* ivalues); -void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues); -void deletePixelFormat(void* pixelFormat); +NSOpenGLPixelFormat* createPixelFormat(int* iattrs, int niattrs, int* ivalues); +void queryPixelFormat(NSOpenGLPixelFormat* fmt, int* iattrs, int niattrs, int* ivalues); +void deletePixelFormat(NSOpenGLPixelFormat* fmt); // NS .. -void *getCurrentContext(void); -void *getNSView(void* nsContext); +NSOpenGLContext* getCurrentContext(void); +CGLContextObj getCGLContext(NSOpenGLContext* ctx); +NSView* getNSView(NSOpenGLContext* ctx); -void* createContext(void* shareContext, - void* nsView, - void* pixelFormat, +NSOpenGLContext* createContext(NSOpenGLContext* shareContext, + NSView* nsView, + Bool isBackingLayerView, + NSOpenGLPixelFormat* pixelFormat, Bool opaque, int* viewNotReady); -void *getCGLContext(void* nsContext); -Bool makeCurrentContext(void* nsContext); -Bool clearCurrentContext(void *nsContext); -Bool deleteContext(void* nsContext, Bool releaseOnMainThread); -Bool flushBuffer(void* nsContext); -void setContextOpacity(void* nsContext, int opacity); -void updateContext(void* nsContext); -void copyContext(void* destContext, void* srcContext, int mask); - -void* updateContextRegister(void* nsContext, void* nsView); +Bool makeCurrentContext(NSOpenGLContext* ctx); +Bool clearCurrentContext(NSOpenGLContext *ctx); +Bool deleteContext(NSOpenGLContext* ctx, Bool releaseOnMainThread); +Bool flushBuffer(NSOpenGLContext* ctx); +void setContextOpacity(NSOpenGLContext* ctx, int opacity); +void updateContext(NSOpenGLContext* ctx); +void copyContext(NSOpenGLContext* dest, NSOpenGLContext* src, int mask); + +void* updateContextRegister(NSOpenGLContext* ctx, NSView* view); Bool updateContextNeedsUpdate(void* updater); void updateContextUnregister(void* updater); -void* createPBuffer(int renderTarget, int internalFormat, int width, int height); -Bool destroyPBuffer(void* pBuffer); -void setContextPBuffer(void* nsContext, void* pBuffer); -void setContextTextureImageToPBuffer(void* nsContext, void* pBuffer, int colorBuffer); +NSOpenGLPixelBuffer* createPBuffer(int renderTarget, int internalFormat, int width, int height); +Bool destroyPBuffer(NSOpenGLPixelBuffer* pBuffer); +void setContextPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer); +void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer, GLenum colorBuffer); + +// NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSView* view, Bool opaque); +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* pbuffer, Bool opaque, int texWidth, int texHeight); +void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval); +void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms); +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* glLayer); +void releaseNSOpenGLLayer(NSOpenGLLayer *glLayer); void* getProcAddress(const char *procName); -void setSwapInterval(void* nsContext, int interval); +void setSwapInterval(NSOpenGLContext* ctx, int interval); /* Gamma-related functionality */ Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp); void resetGammaRamp(); -/****************************************************************************************/ -/* Java2D/JOGL bridge support; need to be able to create pbuffers and - contexts using the CGL APIs to be able to share textures, etc. with - contexts created by Java2D/JOGL bridge, which are CGLContextObjs */ - -/* Pick up copies of CGL signatures from Mac OS X stub_includes/window-system-build directory */ -#include <OpenGL/OpenGL.h> diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java index 93b75e70b..26d299663 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java @@ -164,7 +164,7 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl { } }; - public boolean skipWaitForCompletion(Thread thread) { - return ((Thread.currentThread() == thread) || EventQueue.isDispatchThread()); + public boolean blockUntilDone(Thread thread) { + return ((Thread.currentThread() != thread) && !EventQueue.isDispatchThread()); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java index 16aac957a..a9023886d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java @@ -59,7 +59,9 @@ import javax.media.opengl.GLAutoDrawable; */ public class Animator extends AnimatorBase { - + /** timeout in milliseconds, 15 frames @ 60Hz = 240ms, limiting {@link #finishLifecycleAction(Condition)} */ + private static final long TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION = 15*16; + protected ThreadGroup threadGroup; private Runnable runnable; private boolean runAsFastAsPossible; @@ -241,16 +243,20 @@ public class Animator extends AnimatorBase { // dependencies on the Animator's internal thread. Currently we // use a couple of heuristics to determine whether we should do // the blocking wait(). - boolean doWait = !impl.skipWaitForCompletion(animThread); - if (doWait) { - while (condition.result()) { - try { - wait(); - } catch (InterruptedException ie) { } - } + long remaining = impl.blockUntilDone(animThread) ? TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION : 0; + while (remaining>0 && condition.result()) { + long td = System.currentTimeMillis(); + try { + wait(remaining); + } catch (InterruptedException ie) { } + remaining -= (System.currentTimeMillis() - td) ; } if(DEBUG) { - System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished - waited " + doWait + + if(remaining<0) { + System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): ++++++ timeout reached ++++++ "); + } + System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished "+ + "- waited " + (TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION-remaining) + "/" + TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION + ", started: " + isStartedImpl() +", animating: " + isAnimatingImpl() + ", paused: " + isPausedImpl() + ", drawables " + drawables.size()); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index e84a9bf78..9bea27f45 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -56,7 +56,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { public interface AnimatorImpl { void display(ArrayList<GLAutoDrawable> drawables, boolean ignoreExceptions, boolean printExceptions); - boolean skipWaitForCompletion(Thread thread); + boolean blockUntilDone(Thread thread); } protected ArrayList<GLAutoDrawable> drawables = new ArrayList<GLAutoDrawable>(); @@ -101,7 +101,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { if(paused) { resume(); } - if(!impl.skipWaitForCompletion(animThread)) { + if(impl.blockUntilDone(animThread)) { while(isStarted() && !isPaused() && !isAnimating()) { try { wait(); @@ -123,7 +123,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { if(paused) { resume(); } - if(!impl.skipWaitForCompletion(animThread)) { + if(impl.blockUntilDone(animThread)) { while(isStarted() && drawablesEmpty && isAnimating()) { try { wait(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java index bad268f70..23b0845ee 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java @@ -60,7 +60,7 @@ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl { } } - public boolean skipWaitForCompletion(Thread thread) { - return (Thread.currentThread() == thread); + public boolean blockUntilDone(Thread thread) { + return (Thread.currentThread() != thread); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java index f2e742cda..62441d8b8 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java @@ -491,6 +491,19 @@ public class GLBuffers extends Buffers { return sizeof(gl, tmp, elements * esize, width, height, depth, pack); } + + public static final int getNextPowerOf2(int number) { + if (((number-1) & number) == 0) { + //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 + return number; + } + int power = 0; + while (number > 0) { + number = number>>1; + power++; + } + return (1<<power); + } //---------------------------------------------------------------------- // Conversion routines diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java index b6df365ba..7f3aa8a39 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java @@ -1055,9 +1055,7 @@ public class Texture { // Helper routines for disabling certain codepaths private static boolean haveNPOT(GL gl) { - return (!disableNPOT && - ( gl.isGLES2() || - gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two") ) ); + return !disableNPOT && gl.isNPOTTextureAvailable(); } private static boolean haveTexRect(GL gl) { diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java index f93d443e0..534e449bc 100644 --- a/src/jogl/classes/javax/media/opengl/GLBase.java +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -294,6 +294,17 @@ public interface GLBase { */ public boolean isExtensionAvailable(String glExtensionName); + /** + * Returns true if the GL context supports non power of two (NPOT) textures, + * otherwise false. + * <p> + * NPOT textures are supported in OpenGL >= 3, GLES2 or if the + * 'GL_ARB_texture_non_power_of_two' extension is available. + * </p> + * @return + */ + public boolean isNPOTTextureAvailable(); + /** Provides a platform-independent way to specify the minimum swap interval for buffer swaps. An argument of 0 disables sync-to-vertical-refresh completely, while an argument of 1 diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 9d99a32ff..31125af59 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -45,6 +45,7 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.util.HashMap; import java.util.HashSet; + import javax.media.nativewindow.AbstractGraphicsDevice; import com.jogamp.common.util.IntObjectHashMap; @@ -767,12 +768,12 @@ public abstract class GLContext { /** * @see #getDeviceVersionAvailableKey(javax.media.nativewindow.AbstractGraphicsDevice, int, int) */ - protected static /*final*/ HashMap/*<DeviceVersionAvailableKey, Integer>*/ deviceVersionAvailable = new HashMap(); + protected static /*final*/ HashMap<String, Integer> deviceVersionAvailable = new HashMap<String, Integer>(); /** * @see #getUniqueDeviceString(javax.media.nativewindow.AbstractGraphicsDevice) */ - private static /*final*/ HashSet/*<UniqueDeviceString>*/ deviceVersionsAvailableSet = new HashSet(); + private static /*final*/ HashSet<String> deviceVersionsAvailableSet = new HashSet<String>(); protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { return device.getUniqueID() + "-" + toHexString(compose8bit(major, profile, 0, 0)); @@ -824,7 +825,7 @@ public abstract class GLContext { String key = getDeviceVersionAvailableKey(device, reqMajor, profile); Integer val = new Integer(compose8bit(resMajor, resMinor, resCtp, 0)); synchronized(deviceVersionAvailable) { - val = (Integer) deviceVersionAvailable.put( key, val ); + val = deviceVersionAvailable.put( key, val ); } return val; } @@ -833,7 +834,7 @@ public abstract class GLContext { String key = getDeviceVersionAvailableKey(device, reqMajor, profile); Integer val; synchronized(deviceVersionAvailable) { - val = (Integer) deviceVersionAvailable.get( key ); + val = deviceVersionAvailable.get( key ); } return val; } @@ -875,29 +876,29 @@ public abstract class GLContext { return null != getAvailableGLVersion(device, major, profile); } - public static boolean isGLES1Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); - } + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); + } - public static boolean isGLES2Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); - } + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); + } - public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); - } + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); + } - public static boolean isGL4Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); - } + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); + } - public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); - } + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); + } - public static boolean isGL3Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); - } + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); + } public static boolean isGL2Available(AbstractGraphicsDevice device) { return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT); @@ -941,6 +942,10 @@ public abstract class GLContext { return sb.toString(); } + // + // internal string utils + // + protected static String toString(int val, boolean hex) { if(hex) { return "0x" + Integer.toHexString(val); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java index f4cd77059..2b86a04ba 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java @@ -158,6 +158,12 @@ public interface GLDrawable { */ public GLProfile getGLProfile(); + /** + * Returns the underlying native surface which surface handle + * represents this OpenGL drawable's native resource. + * + * @see #getHandle() + */ public NativeSurface getNativeSurface(); /** diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 92be62b4d..94fb250ce 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -83,6 +83,8 @@ import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; import javax.media.opengl.Threading; import com.jogamp.opengl.util.FBObject; +import com.jogamp.opengl.util.GLBuffers; + import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -776,17 +778,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (number == 0) { return 2; } - - if (((number-1) & number) == 0) { - //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 - return number; - } - int power = 0; - while (number > 0) { - number = number>>1; - power++; - } - return (1<<power); + return GLBuffers.getNextPowerOf2(number); } private int getGLInteger(GL gl, int which) { diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java index 2fa708404..bc9a93042 100644 --- a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java +++ b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java @@ -79,7 +79,7 @@ public class GlyphString { * @param shape is not null, add all {@link GlyphShape}'s {@link Outline} to this instance. * @param vertexFactory vertex impl factory {@link Factory} * @param font the target {@link Font} - * @param size font size + * @param fontSize font size * @param str string text * @return the created {@link GlyphString} instance */ diff --git a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java index 96d62fbb3..27569d210 100644 --- a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java +++ b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java @@ -28,6 +28,8 @@ package jogamp.opengl; import java.io.PrintStream; +import java.util.concurrent.TimeUnit; + import javax.media.opengl.FPSCounter; /** @@ -55,7 +57,7 @@ public class FPSCounterImpl implements FPSCounter { public final synchronized void tickFPS() { fpsTotalFrames++; if(fpsUpdateFramesInterval>0 && fpsTotalFrames%fpsUpdateFramesInterval == 0) { - final long now = System.currentTimeMillis(); + final long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); fpsLastPeriod = now - fpsLastUpdateTime; fpsLastPeriod = Math.max(fpsLastPeriod, 1); // div 0 fpsLast = ( (float)fpsUpdateFramesInterval * 1000f ) / ( (float) fpsLastPeriod ) ; @@ -96,7 +98,7 @@ public class FPSCounterImpl implements FPSCounter { } public final synchronized void resetFPSCounter() { - fpsStartTime = System.currentTimeMillis(); // overwrite startTime to real init one + fpsStartTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); // overwrite startTime to real init one fpsLastUpdateTime = fpsStartTime; fpsLastPeriod = 0; fpsTotalFrames = 0; diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 704f71457..068190cb2 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -40,9 +40,26 @@ package jogamp.opengl; -import java.nio.*; -import javax.media.nativewindow.*; -import javax.media.opengl.*; +import java.nio.Buffer; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.SurfaceChangeable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLException; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; +import javax.media.opengl.Threading; + +import jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.common.util.VersionNumber; @@ -103,24 +120,43 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { if (target == null) { throw new IllegalArgumentException("Null target"); } - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); AbstractGraphicsDevice adevice = config.getScreen().getDevice(); GLDrawable result = null; adevice.lock(); try { - if(caps.isOnscreen()) { - if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target); + if(chosenCaps.isOnscreen()) { + // onscreen + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true); + if(null == ols) { + // traditional onscreen + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target); + } + result = createOnscreenDrawableImpl(target); + } else { + // layered surface -> offscreen/PBuffer + final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable(); + chosenCapsMod.setOnscreen(false); + chosenCapsMod.setPBuffer(canCreateGLPbuffer(adevice)); + config.setChosenCapabilities(chosenCapsMod); + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer: "+target); + } + if( ! ( target instanceof SurfaceChangeable ) ) { + throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target); + } + result = createOffscreenDrawableImpl(target); } - result = createOnscreenDrawableImpl(target); } else { + // offscreen + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+chosenCaps.isPBuffer()+"): "+target); + } if( ! ( target instanceof SurfaceChangeable ) ) { throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen: "+target); } - if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+caps.isPBuffer()+"): "+target); - } result = createOffscreenDrawableImpl(target); } } finally { @@ -287,15 +323,6 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { // GLDrawableFactoryImpl details // - protected void maybeDoSingleThreadedWorkaround(Runnable action) { - if (Threading.isSingleThreaded() && - !Threading.isOpenGLThread()) { - Threading.invokeOnOpenGLThread(action); - } else { - action.run(); - } - } - /** * Returns the sole GLDrawableFactoryImpl instance. * diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index 58c9aaaa6..6b6ce9f9e 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -125,7 +125,10 @@ public abstract class GLDrawableImpl implements GLDrawable { return surface; } + /** called with locked surface @ setRealized(false) */ protected void destroyHandle() {} + + /** called with locked surface @ setRealized(true) or @ lockSurface(..) when surface changed */ protected void updateHandle() {} public long getHandle() { diff --git a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java index 318d00637..6e2b7b744 100644 --- a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java +++ b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java @@ -29,6 +29,7 @@ package jogamp.opengl; import java.util.ArrayList; + import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; @@ -86,6 +87,7 @@ public class GLGraphicsConfigurationUtil { return getWinAttributeBits(caps.isOnscreen(), caps.isPBuffer()); } + @SuppressWarnings({ "rawtypes", "unchecked" }) public static final boolean addGLCapabilitiesPermutations(ArrayList capsBucket, GLCapabilitiesImmutable temp, int winattrbits) { int preSize = capsBucket.size(); if( 0 != ( WINDOW_BIT & winattrbits ) ) { @@ -138,7 +140,7 @@ public class GLGraphicsConfigurationUtil { if( capsRequested.getDoubleBuffered() || capsRequested.isOnscreen() || !capsRequested.isPBuffer()) { // fix caps .. GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); - caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN + caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN - we don't need to be single buffered .. caps2.setOnscreen(false); caps2.setPBuffer(true); return caps2; diff --git a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java index 2c396e265..5979056f3 100644 --- a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java +++ b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java @@ -61,7 +61,7 @@ public class SharedResourceRunner implements Runnable { String initConnection = null; String releaseConnection = null; - HashSet devicesTried = new HashSet(); + HashSet<String> devicesTried = new HashSet<String>(); private boolean getDeviceTried(String connection) { synchronized (devicesTried) { @@ -86,7 +86,7 @@ public class SharedResourceRunner implements Runnable { public SharedResourceRunner.Resource getOrCreateShared(AbstractGraphicsDevice device) { SharedResourceRunner.Resource sr = null; if(null != device) { - String connection = device.getConnection(); + final String connection = device.getConnection(); sr = impl.mapGet(connection); if (null == sr && !getDeviceTried(connection)) { addDeviceTried(connection); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index a9cc40335..de10b066d 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -197,6 +197,16 @@ public abstract class EGLDrawable extends GLDrawableImpl { } } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { + if(DEBUG) { + System.err.println("eglSwapBuffers failed:"); + Thread.dumpStack(); + } + } + } + public int getWidth() { int[] tmp = new int[1]; if (!EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_WIDTH, tmp, 0)) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 79d96bdb6..decc74258 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -268,7 +268,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { WrappedSurface ns = new WrappedSurface(EGLGraphicsConfigurationFactory.createOffscreenGraphicsConfiguration(device, capsChosen, capsRequested, chooser)); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 4fb3dca78..ea625fb27 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -38,15 +38,25 @@ package jogamp.opengl.egl; import java.nio.IntBuffer; import java.util.ArrayList; -import javax.media.nativewindow.*; -import javax.media.nativewindow.egl.*; -import javax.media.opengl.*; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.egl.EGLGraphicsDevice; +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.MutableGraphicsConfiguration; +import jogamp.opengl.Debug; +import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; -import jogamp.opengl.*; -public class EGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); public final long getNativeConfig() { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java index 7d5e0448d..42f067b29 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java @@ -55,15 +55,5 @@ public class EGLOnscreenDrawable extends EGLDrawable { protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { return EGL.eglCreateWindowSurface(eglDpy, eglNativeCfg, surfaceHandle, null); } - - protected void swapBuffersImpl() { - if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { - if(DEBUG) { - System.err.println("eglSwapBuffers failed:"); - Thread.dumpStack(); - } - } - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java index 5fb32e6cd..be6c80c41 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java @@ -40,48 +40,40 @@ package jogamp.opengl.egl; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.SurfaceChangeable; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; -import jogamp.opengl.x11.glx.GLX; - public class EGLPbufferDrawable extends EGLDrawable { private int texFormat; protected static final boolean useTexture = false; // No yet .. protected EGLPbufferDrawable(EGLDrawableFactory factory, NativeSurface target) { super(factory, target); + setRealized(true); + } - // get choosen ones .. - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) - getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + protected void destroyImpl() { + setRealized(false); + } + + protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { + final AbstractGraphicsConfiguration config = getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(useTexture) { - this.texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB ; + texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB ; } else { - this.texFormat = EGL.EGL_NO_TEXTURE; + texFormat = EGL.EGL_NO_TEXTURE; } if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); + System.out.println("Pbuffer config: " + config); } - setRealized(true); - - if (DEBUG) { - System.out.println("Created pbuffer: " + this); - } - - } - - protected void destroyImpl() { - setRealized(false); - } - - protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { NativeSurface nw = getNativeSurface(); int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(nw.getWidth(), nw.getHeight(), texFormat); long surf = EGL.eglCreatePbufferSurface(eglDpy, eglNativeCfg, attrs, 0); @@ -97,11 +89,5 @@ public class EGLPbufferDrawable extends EGLDrawable { public GLContext createContext(GLContext shareWith) { return new EGLPbufferContext(this, shareWith); } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 1fe47f60b..f5970fad9 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -45,7 +45,9 @@ import java.util.Map; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; -import javax.media.nativewindow.DefaultGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; @@ -63,7 +65,6 @@ import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; - public abstract class MacOSXCGLContext extends GLContextImpl { // Abstract interface for implementation of this context (either @@ -76,7 +77,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl boolean makeCurrent(long ctx); boolean release(long ctx); boolean setSwapInterval(int interval); - boolean swapBuffers(boolean isOnscreen); + boolean swapBuffers(); } /* package */ static final boolean isTigerOrLater; @@ -268,9 +269,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl } protected void swapBuffers() { - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - if(!impl.swapBuffers(caps.isOnscreen())) { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!impl.swapBuffers()) { throw new GLException("Error swapping buffers: "+this); } } @@ -282,12 +282,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(!impl.setSwapInterval(interval)) { throw new GLException("Error set swap-interval: "+this); } - if ( isNSContext() ) { - CGL.setSwapInterval(contextHandle, interval); - } else { - int[] lval = new int[] { (int) interval } ; - CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); - } currentSwapInterval = interval ; } @@ -403,31 +397,44 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { + long nsOpenGLLayer = 0; + long nsOpenGLLayerPFmt = 0; + public boolean isNSContext() { return true; } public long create(long share, int ctp, int major, int minor) { long ctx = 0; - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) MacOSXCGLContext.this.drawable; + final NativeSurface surface = drawable.getNativeSurface(); + final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); if (pixelFormat == 0) { throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); } config.setChosenPixelFormat(pixelFormat); + if(DEBUG) { + System.err.println("NS create OSX>=lion "+isLionOrLater); + System.err.println("NS create backingLayerHost: "+backingLayerHost); + System.err.println("NS create share: "+share); + System.err.println("NS create chosenCaps: "+chosenCaps); + System.err.println("NS create pixelFormat: "+toHexString(pixelFormat)); + System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); + System.err.println("NS create drawable NSView-handle: "+toHexString(drawable.getNSViewHandle())); + // Thread.dumpStack(); + } try { int[] viewNotReady = new int[1]; // Try to allocate a context with this ctx = CGL.createContext(share, - drawable.getHandle(), + drawable.getNSViewHandle(), null!=backingLayerHost, pixelFormat, chosenCaps.isBackgroundOpaque(), viewNotReady, 0); if (0 == ctx) { - if (viewNotReady[0] == 1) { - if (DEBUG) { - System.err.println("!!! View not ready for " + getClass().getName()); - } - // View not ready at the window system level + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); } return 0; } @@ -439,22 +446,63 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(DEBUG) { GLCapabilitiesImmutable caps0 = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(null, pixelFormat); - System.err.println("NS created(>=lion "+isLionOrLater+"): "+caps0); + System.err.println("NS create pixelformat2GLCaps: "+caps0); + } + GLCapabilitiesImmutable fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); + fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); + config.setChosenCapabilities(fixedCaps); + if(DEBUG) { + System.err.println("NS create fixedCaps: "+fixedCaps); } - GLCapabilitiesImmutable caps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); - caps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(caps, chosenCaps.isBackgroundOpaque()); - config.setChosenCapabilities(caps); - if(caps.isPBuffer()) { + if(fixedCaps.isPBuffer()) { // Must now associate the pbuffer with our newly-created context CGL.setContextPBuffer(ctx, drawable.getHandle()); - } + } + // + // handled layered surface + // + if(null != backingLayerHost) { + nsOpenGLLayerPFmt = pixelFormat; + pixelFormat = 0; + final int texWidth, texHeight; + if(drawable instanceof MacOSXPbufferCGLDrawable) { + final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; + texWidth = osxPDrawable.getTextureWidth(); + texHeight = osxPDrawable.getTextureHeight(); + } else { + texWidth = drawable.getWidth(); + texHeight = drawable.getHeight(); + } + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, drawable.getHandle(), fixedCaps.isBackgroundOpaque(), texWidth, texHeight); + if (DEBUG) { + System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)); + } + backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); + } } finally { - CGL.deletePixelFormat(pixelFormat); + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + } } return ctx; } public boolean destroy(long ctx) { + if(0 != nsOpenGLLayer) { + final NativeSurface surface = drawable.getNativeSurface(); + if (DEBUG) { + System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)); + } + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + if(null == ols) { + throw new InternalError("XXX: "+ols); + } + CGL.releaseNSOpenGLLayer(nsOpenGLLayer); + ols.detachSurfaceLayer(nsOpenGLLayer); + CGL.deletePixelFormat(nsOpenGLLayerPFmt); + nsOpenGLLayerPFmt = 0; + nsOpenGLLayer = 0; + } return CGL.deleteContext(ctx, true); } @@ -472,14 +520,26 @@ public abstract class MacOSXCGLContext extends GLContextImpl } public boolean setSwapInterval(int interval) { - CGL.setSwapInterval(contextHandle, interval); + if(0 != nsOpenGLLayer) { + CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); + } + CGL.setSwapInterval(contextHandle, interval); return true; } - public boolean swapBuffers(boolean isOnscreen) { - if(isOnscreen) { - return CGL.flushBuffer(contextHandle); - } - return true; + + public boolean swapBuffers() { + if(0 != nsOpenGLLayer) { + // sync w/ CALayer renderer - wait until next frame is required (v-sync) + CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, 16); // timeout 16ms -> 60Hz + } + if(CGL.flushBuffer(contextHandle)) { + if(0 != nsOpenGLLayer) { + // trigger CALayer to update + CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer); + } + return true; + } + return false; } } @@ -547,11 +607,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); return true; } - public boolean swapBuffers(boolean isOnscreen) { - if(isOnscreen) { - return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); - } - return true; + public boolean swapBuffers() { + return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index 5a35f661d..12d480fd1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -40,6 +40,11 @@ package jogamp.opengl.macosx.cgl; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -87,18 +92,46 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { this.id = id; } } - + private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); + private boolean haveSetOpenGLMode = false; private GLBackendType openGLMode = GLBackendType.NSOPENGL; public MacOSXCGLDrawable(GLDrawableFactory factory, NativeSurface comp, boolean realized) { super(factory, comp, realized); - initOpenGLImpl(getOpenGLMode()); - } - + initOpenGLImpl(getOpenGLMode()); + } + protected void setRealizedImpl() { } + protected long getNSViewHandle() { + return GLBackendType.NSOPENGL == openGLMode ? getHandle() : null; + } + + protected void registerContext(MacOSXCGLContext ctx) { + // NOTE: we need to keep track of the created contexts in order to + // implement swapBuffers() because of how Mac OS X implements its + // OpenGL window interface + synchronized (createdContexts) { + createdContexts.add(new WeakReference<MacOSXCGLContext>(ctx)); + } + } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + synchronized (createdContexts) { + for (Iterator<WeakReference<MacOSXCGLContext>> iter = createdContexts.iterator(); iter.hasNext(); ) { + WeakReference<MacOSXCGLContext> ref = iter.next(); + MacOSXCGLContext ctx = ref.get(); + if (ctx != null) { + ctx.swapBuffers(); + } else { + iter.remove(); + } + } + } + } + public GLDynamicLookupHelper getGLDynamicLookupHelper() { return getFactoryImpl().getGLDynamicLookupHelper(0); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 5c726bc54..30917476e 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -42,6 +42,7 @@ package jogamp.opengl.macosx.cgl; import java.nio.Buffer; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import javax.media.nativewindow.AbstractGraphicsConfiguration; @@ -52,6 +53,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.macosx.MacOSXGraphicsDevice; +import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; @@ -113,18 +115,28 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { // private MacOSXCGLContext context; MacOSXGraphicsDevice device; boolean wasContextCreated; + boolean hasNPOTTextures; + boolean hasRECTTextures; + boolean hasAppletFloatPixels; - SharedResource(MacOSXGraphicsDevice device, boolean wasContextCreated + SharedResource(MacOSXGraphicsDevice device, boolean wasContextCreated, + boolean hasNPOTTextures, boolean hasRECTTextures, boolean hasAppletFloatPixels /* MacOSXCGLDrawable draw, MacOSXCGLContext ctx */) { // drawable = draw; // context = ctx; this.device = device; this.wasContextCreated = wasContextCreated; + this.hasNPOTTextures = hasNPOTTextures; + this.hasRECTTextures = hasRECTTextures; + this.hasAppletFloatPixels = hasAppletFloatPixels; } final MacOSXGraphicsDevice getDevice() { return device; } final boolean wasContextAvailable() { return wasContextCreated; } + final boolean isNPOTTextureAvailable() { return hasNPOTTextures; } + final boolean isRECTTextureAvailable() { return hasRECTTextures; } + final boolean isAppletFloatPixelsAvailable() { return hasAppletFloatPixels; } } - HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + HashMap<String, SharedResource> sharedMap = new HashMap<String, SharedResource>(); MacOSXGraphicsDevice defaultDevice; public final AbstractGraphicsDevice getDefaultDevice() { @@ -138,52 +150,78 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return false; } - private boolean isOSXContextAvailable(AbstractGraphicsDevice sharedDevice) { - boolean madeCurrent = false; - GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); - if (null == glp) { - throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); - } - final GLCapabilities caps = new GLCapabilities(glp); - caps.setRedBits(5); caps.setGreenBits(5); caps.setBlueBits(5); caps.setAlphaBits(0); - caps.setDoubleBuffered(false); - caps.setOnscreen(false); - caps.setPBuffer(true); - final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) createGLDrawable( createOffscreenSurfaceImpl(sharedDevice, caps, caps, null, 64, 64) ); - if(null!=drawable) { - final GLContext context = drawable.createContext(null); - if (null != context) { - context.setSynchronized(true); - try { - context.makeCurrent(); // could cause exception - madeCurrent = context.isCurrent(); - } catch (GLException gle) { - if (DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.createShared: INFO: makeCurrent failed"); - gle.printStackTrace(); - } - } finally { - context.destroy(); - } - } - drawable.destroy(); - } - return madeCurrent; + private HashSet<String> devicesTried = new HashSet<String>(); + + private boolean getDeviceTried(String connection) { + synchronized (devicesTried) { + return devicesTried.contains(connection); + } + } + private void addDeviceTried(String connection) { + synchronized (devicesTried) { + devicesTried.add(connection); + } + } + private void removeDeviceTried(String connection) { + synchronized (devicesTried) { + devicesTried.remove(connection); + } } /* package */ SharedResource getOrCreateOSXSharedResource(AbstractGraphicsDevice adevice) { - String connection = adevice.getConnection(); + final String connection = adevice.getConnection(); SharedResource sr; synchronized(sharedMap) { - sr = (SharedResource) sharedMap.get(connection); + sr = sharedMap.get(connection); } - if(null==sr) { + if(null==sr && !getDeviceTried(connection)) { + addDeviceTried(connection); final MacOSXGraphicsDevice sharedDevice = new MacOSXGraphicsDevice(adevice.getUnitID()); - final boolean madeCurrent = isOSXContextAvailable(sharedDevice); - sr = new SharedResource(sharedDevice, madeCurrent); + boolean madeCurrent = false; + boolean hasNPOTTextures = false; + boolean hasRECTTextures = false; + boolean hasAppletFloatPixels = false; + { + GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); + if (null == glp) { + throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); + } + final GLCapabilities caps = new GLCapabilities(glp); + caps.setRedBits(5); caps.setGreenBits(5); caps.setBlueBits(5); caps.setAlphaBits(0); + caps.setDoubleBuffered(false); + caps.setOnscreen(false); + caps.setPBuffer(true); + final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) createGLDrawable( createOffscreenSurfaceImpl(sharedDevice, caps, caps, null, 64, 64) ); + if(null!=drawable) { + final GLContext context = drawable.createContext(null); + if (null != context) { + context.setSynchronized(true); + try { + context.makeCurrent(); // could cause exception + madeCurrent = context.isCurrent(); + if(madeCurrent) { + GL gl = context.getGL(); + hasNPOTTextures = gl.isNPOTTextureAvailable(); + hasRECTTextures = gl.isExtensionAvailable("GL_EXT_texture_rectangle"); + hasAppletFloatPixels = gl.isExtensionAvailable("GL_APPLE_float_pixels"); + } + } catch (GLException gle) { + if (DEBUG) { + System.err.println("MacOSXCGLDrawableFactory.createShared: INFO: makeCurrent failed"); + gle.printStackTrace(); + } + } finally { + context.destroy(); + } + } + drawable.destroy(); + } + } + sr = new SharedResource(sharedDevice, madeCurrent, hasNPOTTextures, hasRECTTextures, hasAppletFloatPixels); synchronized(sharedMap) { sharedMap.put(connection, sr); } + removeDeviceTried(connection); if (DEBUG) { System.err.println("MacOSXCGLDrawableFactory.createShared: device: " + sharedDevice); System.err.println("MacOSXCGLDrawableFactory.createShared: context: " + madeCurrent); @@ -232,22 +270,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { if(!caps.isPBuffer()) { return new MacOSXOffscreenCGLDrawable(this, target); } - - // PBuffer GLDrawable Creation - /** - * FIXME: Think about this .. - * should not be necessary ? .. - final List returnList = new ArrayList(); - final GLDrawableFactory factory = this; - Runnable r = new Runnable() { - public void run() { - returnList.add(new MacOSXPbufferCGLDrawable(factory, target)); - } - }; - maybeDoSingleThreadedWorkaround(r); - return (GLDrawableImpl) returnList.get(0); - */ - return new MacOSXPbufferCGLDrawable(this, target); + return new MacOSXPbufferCGLDrawable(this, target, true); } public boolean canCreateGLPbuffer(AbstractGraphicsDevice device) { @@ -257,7 +280,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device,GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { AbstractGraphicsScreen screen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_MACOSX); WrappedSurface ns = new WrappedSurface(MacOSXCGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, true)); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java index a429720db..f552ab3dd 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java @@ -41,15 +41,16 @@ import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.MutableGraphicsConfiguration; + import com.jogamp.common.nio.PointerBuffer; -public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { long pixelformat; MacOSXCGLGraphicsConfiguration(AbstractGraphicsScreen screen, @@ -67,10 +68,6 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration this.pixelformat=pixelformat; } - void setChosenCapabilities(GLCapabilitiesImmutable caps) { - super.setChosenCapabilities(caps); - } - protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(MacOSXCGLDrawableFactory factory, AbstractGraphicsDevice device) { MacOSXCGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateOSXSharedResource(device); if(null == sharedResource) { @@ -83,6 +80,8 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration static final int[] cglInternalAttributeToken = new int[] { CGL.kCGLPFAOpenGLProfile, CGL.kCGLPFAColorFloat, + CGL.NSOpenGLPFANoRecovery, + CGL.NSOpenGLPFAAccelerated, CGL.NSOpenGLPFAPixelBuffer, CGL.NSOpenGLPFADoubleBuffer, CGL.NSOpenGLPFAStereo, @@ -114,6 +113,13 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration ivalues[idx] = caps.getPbufferFloatingPointBuffers() ? 1 : 0; break; + case CGL.NSOpenGLPFANoRecovery: + ivalues[idx] = caps.getHardwareAccelerated() ? 1 : 0; + break; + case CGL.NSOpenGLPFAAccelerated: + ivalues[idx] = caps.getHardwareAccelerated() ? 1 : 0; + break; + case CGL.NSOpenGLPFAPixelBuffer: ivalues[idx] = caps.isPBuffer() ? 1 : 0; break; @@ -222,7 +228,7 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration // Use attribute array to select pixel format PointerBuffer fmt = PointerBuffer.allocateDirect(1); - long[] numScreens = new long[1]; + int[] numScreens = new int[1]; int res = CGL.CGLChoosePixelFormat(attrs, 0, fmt, numScreens, 0); if (res != CGL.kCGLNoError) { throw new GLException("Error code " + res + " while choosing pixel format"); @@ -285,6 +291,10 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration caps.setPbufferFloatingPointBuffers(ivalues[i] != 0); break; + case CGL.NSOpenGLPFAAccelerated: + caps.setHardwareAccelerated(ivalues[i] != 0); + break; + case CGL.NSOpenGLPFAPixelBuffer: caps.setPBuffer(ivalues[i] != 0); break; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java index 08a531200..ba384fc71 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java @@ -48,7 +48,6 @@ import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; -import javax.media.opengl.GLProfile; import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.GLContextShareSet; @@ -61,7 +60,7 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { private MacOSXExternalCGLContext(Drawable drawable, boolean isNSContext, long handle) { super(drawable, null); setOpenGLMode(isNSContext ? GLBackendType.NSOPENGL : GLBackendType.CGL ); - drawable.setExternalCGLContext(this); + drawable.registerContext(this); this.contextHandle = handle; GLContextShareSet.contextCreated(this); setGLFunctionAvailability(false, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); @@ -150,16 +149,10 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { // Need to provide the display connection to extension querying APIs static class Drawable extends MacOSXCGLDrawable { - MacOSXExternalCGLContext extCtx; - Drawable(GLDrawableFactory factory, NativeSurface comp) { super(factory, comp, true); } - void setExternalCGLContext(MacOSXExternalCGLContext externalContext) { - extCtx = externalContext; - } - public GLContext createContext(GLContext shareWith) { throw new GLException("Should not call this"); } @@ -175,11 +168,5 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { public void setSize(int width, int height) { throw new GLException("Should not call this"); } - - protected void swapBuffersImpl() { - if (extCtx != null) { - extCtx.swapBuffers(); - } - } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java index bec4cf32a..ae3fa1428 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java @@ -40,15 +40,15 @@ package jogamp.opengl.macosx.cgl; -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import jogamp.opengl.*; +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; public class MacOSXOffscreenCGLDrawable extends MacOSXPbufferCGLDrawable { public MacOSXOffscreenCGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target); + super(factory, target, true); } public GLContext createContext(GLContext shareWith) { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java index 97d198c92..4fe6fa484 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java @@ -57,7 +57,13 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { @Override protected void drawableUpdatedNotify() throws GLException { - if(0==updateHandle || CGL.updateContextNeedsUpdate(updateHandle)) { + final int w = drawable.getWidth(); + final int h = drawable.getHeight(); + final boolean updateContext = ( 0!=updateHandle && CGL.updateContextNeedsUpdate(updateHandle) ) || + w != lastWidth || h != lastHeight; + if(updateContext) { + lastWidth = w; + lastHeight = h; if (contextHandle == 0) { throw new GLException("Context not created"); } @@ -65,11 +71,11 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { } } - protected long updateHandle = 0; - @Override protected boolean createImpl() { boolean res = super.createImpl(); + lastWidth = -1; + lastHeight = -1; if(res && isNSContext()) { if(0 != updateHandle) { throw new InternalError("XXX1"); @@ -89,5 +95,8 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { updateHandle = 0; } super.destroyImpl(); - } + } + + private long updateHandle = 0; + private int lastWidth, lastHeight; } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java index 24276c39e..80c54042f 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java @@ -40,44 +40,20 @@ package jogamp.opengl.macosx.cgl; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; public class MacOSXOnscreenCGLDrawable extends MacOSXCGLDrawable { - private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); - + protected MacOSXOnscreenCGLDrawable(GLDrawableFactory factory, NativeSurface component) { super(factory, component, false); } public GLContext createContext(GLContext shareWith) { - MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); - // NOTE: we need to keep track of the created contexts in order to - // implement swapBuffers() because of how Mac OS X implements its - // OpenGL window interface - synchronized (createdContexts) { - createdContexts.add(new WeakReference<MacOSXCGLContext>(ctx)); - } + final MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); + registerContext(ctx); return ctx; } - protected void swapBuffersImpl() { - synchronized (createdContexts) { - for (Iterator<WeakReference<MacOSXCGLContext>> iter = createdContexts.iterator(); iter.hasNext(); ) { - WeakReference<MacOSXCGLContext> ref = iter.next(); - MacOSXCGLContext ctx = ref.get(); - if (ctx != null) { - ctx.swapBuffers(); - } else { - iter.remove(); - } - } - } - } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java index c5743b923..f4b71d37d 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java @@ -33,19 +33,14 @@ package jogamp.opengl.macosx.cgl; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; - public class MacOSXPbufferCGLContext extends MacOSXCGLContext { // State for render-to-texture and render-to-texture-rectangle support - private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV private int texture; // actual texture object public MacOSXPbufferCGLContext(MacOSXPbufferCGLDrawable drawable, @@ -55,7 +50,7 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { public void bindPbufferToTexture() { GL gl = getGL(); - gl.glBindTexture(textureTarget, texture); + gl.glBindTexture(((MacOSXPbufferCGLDrawable)drawable).getTextureTarget(), texture); // FIXME: not clear whether this is really necessary, but since // the API docs seem to imply it is and since it doesn't seem to // impact performance, leaving it in @@ -70,18 +65,10 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { if (newCreated) { // Initialize render-to-texture support if requested - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GL gl = getGL(); - boolean rect = gl.isGL2GL3() && capabilities.getPbufferRenderToTextureRectangle(); - if (rect) { - if (!gl.isExtensionAvailable("GL_EXT_texture_rectangle")) { - System.err.println("MacOSXPbufferCGLContext: WARNING: GL_EXT_texture_rectangle extension not " + - "supported; skipping requested render_to_texture_rectangle support for pbuffer"); - rect = false; - } - } - textureTarget = (rect ? GL2.GL_TEXTURE_RECTANGLE : GL.GL_TEXTURE_2D); + final GL gl = getGL(); + final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; + final int textureTarget = osxPDrawable.getTextureTarget(); + int[] tmp = new int[1]; gl.glGenTextures(1, tmp, 0); texture = tmp[0]; @@ -90,7 +77,9 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); - gl.glCopyTexImage2D(textureTarget, 0, GL.GL_RGB, 0, 0, drawable.getWidth(), drawable.getHeight(), 0); + gl.glTexImage2D(textureTarget, 0, GL.GL_RGB, osxPDrawable.getTextureWidth(), osxPDrawable.getTextureHeight(), + 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, null); + gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, drawable.getWidth(), drawable.getHeight()); } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java index fdbfaf6d6..4c985fd00 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java @@ -51,14 +51,10 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import jogamp.opengl.Debug; - import com.jogamp.common.nio.PointerBuffer; +import com.jogamp.opengl.util.GLBuffers; - -public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { - private static final boolean DEBUG = Debug.debug("MacOSXPbufferCGLDrawable"); - +public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // Abstract interface for implementation of this drawable (either // NSOpenGL-based or CGL-based) interface GLBackendImpl { @@ -76,34 +72,50 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // Note that we can not store this in the NativeSurface because the // semantic is that contains an NSView protected long pBuffer; + protected int pBufferTexTarget, pBufferTexWidth, pBufferTexHeight; - public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(); + public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target, boolean realizeNow) { + super(factory, target, false); - if (DEBUG) { - System.err.println("Created pbuffer " + this); + if(realizeNow) { + setRealized(true); } } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } public GLContext createContext(GLContext shareWith) { - return new MacOSXPbufferCGLContext(this, shareWith); + final MacOSXPbufferCGLContext ctx = new MacOSXPbufferCGLContext(this, shareWith); + registerContext(ctx); + return ctx; } - protected void destroyImpl() { + @Override + protected long getNSViewHandle() { + // pbuffer handle is NSOpenGLPixelBuffer + return 0; + } + + @Override + public long getHandle() { + return pBuffer; + } + + protected int getTextureTarget() { return pBufferTexTarget; } + protected int getTextureWidth() { return pBufferTexWidth; } + protected int getTextureHeight() { return pBufferTexHeight; } + + protected void destroyPbuffer() { if (this.pBuffer != 0) { NativeSurface ns = getNativeSurface(); impl.destroy(pBuffer); @@ -112,73 +124,56 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { } } - public long getHandle() { - return pBuffer; - } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); + private void createPbuffer() { + final NativeSurface ns = getNativeSurface(); + final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + final GLProfile glProfile = capabilities.getGLProfile(); + MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory)factory).getOrCreateOSXSharedResource(config.getScreen().getDevice()); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); } - } - private void createPbuffer() { - NativeSurface ns = getNativeSurface(); - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GLProfile glProfile = capabilities.getGLProfile(); - int renderTarget; - if (glProfile.isGL2GL3() && capabilities.getPbufferRenderToTextureRectangle()) { - renderTarget = GL2.GL_TEXTURE_RECTANGLE; + if ( capabilities.getPbufferRenderToTextureRectangle() && null!=sr && sr.isRECTTextureAvailable() ) { + pBufferTexTarget = GL2.GL_TEXTURE_RECTANGLE; + } else { + pBufferTexTarget = GL.GL_TEXTURE_2D; + } + if ( GL2.GL_TEXTURE_RECTANGLE == pBufferTexTarget || ( null!=sr && sr.isNPOTTextureAvailable() ) ) { + pBufferTexWidth = getWidth(); + pBufferTexHeight = getHeight(); } else { - int w = getNextPowerOf2(getWidth()); - int h = getNextPowerOf2(getHeight()); - ((SurfaceChangeable)ns).setSize(w, h); - renderTarget = GL.GL_TEXTURE_2D; + pBufferTexWidth = GLBuffers.getNextPowerOf2(getWidth()); + pBufferTexHeight = GLBuffers.getNextPowerOf2(getHeight()); } int internalFormat = GL.GL_RGBA; if (capabilities.getPbufferFloatingPointBuffers()) { - // FIXME: want to check availability of GL_APPLE_float_pixels - // extension, but need valid OpenGL context in order to do so -- - // in worst case would need to create dummy window / GLCanvas - // (undesirable) -- could maybe also do this with pbuffers - /* - if (!gl.isExtensionAvailable("GL_APPLE_float_pixels")) { - throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); - } - */ - if(glProfile.isGL2GL3()) { - switch (capabilities.getRedBits()) { + if(!glProfile.isGL2GL3() || null==sr || sr.isAppletFloatPixelsAvailable()) { + throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); + } + switch (capabilities.getRedBits()) { case 16: internalFormat = GL2.GL_RGBA_FLOAT16_APPLE; break; case 32: internalFormat = GL2.GL_RGBA_FLOAT32_APPLE; break; default: throw new GLException("Invalid floating-point bit depth (only 16 and 32 supported)"); - } - } else { - internalFormat = GL.GL_RGBA; } } - - pBuffer = impl.create(renderTarget, internalFormat, getWidth(), getHeight()); + + pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); + if(DEBUG) { + System.err.println("MacOSXPbufferCGLDrawable tex: target "+toHexString(pBufferTexTarget)+ + ", pbufferSize "+getWidth()+"x"+getHeight()+ + ", texSize "+pBufferTexWidth+"x"+pBufferTexHeight+ + ", internal-fmt "+toHexString(internalFormat)); + System.err.println("MacOSXPbufferCGLDrawable pBuffer: "+toHexString(pBuffer)); + // Thread.dumpStack(); + } if (pBuffer == 0) { throw new GLException("pbuffer creation error: CGL.createPBuffer() failed"); } ((SurfaceChangeable)ns).setSurfaceHandle(pBuffer); - - } - - private int getNextPowerOf2(int number) { - if (((number-1) & number) == 0) { - //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 - return number; - } - int power = 0; - while (number > 0) { - number = number>>1; - power++; - } - return (1<<power); } public void setOpenGLMode(GLBackendType mode) { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java index b2c95de39..aa5da9f2b 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java @@ -57,15 +57,19 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { private long hbitmap; protected WindowsBitmapWGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - create(); + super(factory, target, false); + setRealized(true); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - create(); + createBitmap(); } else { - destroyImpl(); + destroyBitmap(); } } @@ -73,7 +77,7 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { return new WindowsBitmapWGLContext(this, shareWith); } - private void create() { + private void createBitmap() { int werr; NativeSurface ns = getNativeSurface(); if(DEBUG) { @@ -153,7 +157,7 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { config.updateGraphicsConfiguration(getFactory(), ns, null); } - protected void destroyImpl() { + protected void destroyBitmap() { NativeSurface ns = getNativeSurface(); if (ns.getSurfaceHandle() != 0) { // Must destroy bitmap and device context @@ -165,11 +169,4 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { ((SurfaceChangeable)ns).setSurfaceHandle(0); } } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } - } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java index 3d0cce725..966ad867f 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java @@ -84,7 +84,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { GLCapabilities caps = new GLCapabilities(glp); WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfigurationFactory.createDefaultGraphicsConfiguration(caps, absScreen); GDISurface ns = new GDISurface(cfg, windowHandle); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return new WindowsDummyWGLDrawable(factory, ns, handleWindowLifecycle); } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java index 7be2c1ac7..cda839967 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java @@ -51,6 +51,7 @@ import javax.media.opengl.GLProfile; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory.SharedResource; import javax.media.opengl.GLCapabilitiesImmutable; @@ -60,27 +61,22 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { private long buffer; // pbuffer handle private int floatMode; - - protected WindowsPbufferWGLDrawable(GLDrawableFactory factory, NativeSurface target, - WindowsWGLDrawableFactory.SharedResource sharedResource) { - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(sharedResource); - - if (DEBUG) { - System.err.println("Created pbuffer " + this); - } + + protected WindowsPbufferWGLDrawable(GLDrawableFactory factory, NativeSurface target) { + super(factory, target, false); + + setRealized(true); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - throw new GLException("Recreation via setRealized not supported."); + createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } @@ -88,7 +84,7 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { return new WindowsPbufferWGLContext(this, shareWith); } - protected void destroyImpl() { + protected void destroyPbuffer() { NativeSurface ns = getNativeSurface(); if(0!=buffer) { WGLExt wglExt = cachedWGLExt; @@ -120,23 +116,22 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { return floatMode; } - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } - - private void createPbuffer(WindowsWGLDrawableFactory.SharedResource sharedResource) { + private void createPbuffer() { + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + SharedResource sharedResource = ((WindowsWGLDrawableFactory)factory).getOrCreateSharedResource(config.getScreen().getDevice()); long parentHdc = sharedResource.getDrawable().getNativeSurface().getSurfaceHandle(); WGLExt wglExt = sharedResource.getContext().getWGLExt(); + if (DEBUG) { + System.out.println("Pbuffer config: " + config); + } + int[] iattributes = new int [2*WindowsWGLGraphicsConfiguration.MAX_ATTRIBS]; float[] fattributes = new float[1]; int[] floatModeTmp = new int[1]; int niattribs = 0; int width, height; - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); GLProfile glProfile = chosenCaps.getGLProfile(); @@ -260,7 +255,7 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { width = tmp[0]; wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_HEIGHT_ARB, tmp, 0 ); height = tmp[0]; - ((SurfaceChangeable)ns).setSize(width, height); + ((SurfaceChangeable)ns).surfaceSizeChanged(width, height); } private static String wglGetLastError() { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java index 4ed9a00c3..fe446e8fe 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java @@ -41,6 +41,7 @@ package jogamp.opengl.windows.wgl; import java.security.AccessController; + import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -74,7 +75,8 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl { } } - protected void swapBuffersImpl() { + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() long startTime = 0; if (PROFILING) { startTime = System.currentTimeMillis(); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index cd22127a3..5a1f997a6 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -436,33 +436,32 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } // PBuffer GLDrawable Creation + GLDrawableImpl pbufferDrawable; final AbstractGraphicsDevice device = config.getScreen().getDevice(); + /** + * Similar to ATI Bug https://bugzilla.mozilla.org/show_bug.cgi?id=486277, + * we need to have a context current on the same Display to create a PBuffer. + */ final SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); - if(null==sr) { - throw new IllegalArgumentException("No shared resource for "+device); - } - final List returnList = new ArrayList(); - Runnable r = new Runnable() { - public void run() { - GLContext lastContext = GLContext.getCurrent(); - if (lastContext != null) { + if(null!=sr) { + GLContext lastContext = GLContext.getCurrent(); + if (lastContext != null) { lastContext.release(); - } - sr.context.makeCurrent(); - try { - GLDrawableImpl pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target, sr); - returnList.add(pbufferDrawable); - } finally { + } + sr.context.makeCurrent(); + try { + pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); + } finally { sr.context.release(); if (lastContext != null) { lastContext.makeCurrent(); } - } } - }; - maybeDoSingleThreadedWorkaround(r); - return (GLDrawableImpl) returnList.get(0); + } else { + pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); + } + return pbufferDrawable; } /** @@ -489,7 +488,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { AbstractGraphicsScreen screen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS); WrappedSurface ns = new WrappedSurface(WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( capsChosen, capsRequested, chooser, screen) ); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java index 989906514..d472d0358 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.List; import javax.media.nativewindow.AbstractGraphicsScreen; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.GL; @@ -48,13 +47,14 @@ import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.windows.DWM_BLURBEHIND; import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.MARGINS; import jogamp.nativewindow.windows.PIXELFORMATDESCRIPTOR; import jogamp.opengl.GLGraphicsConfigurationUtil; -public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { // Keep this under the same debug flag as the drawable factory for convenience protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); @@ -733,10 +733,10 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor(long hdc, int pfdID) { PIXELFORMATDESCRIPTOR pfd = PIXELFORMATDESCRIPTOR.create(); - pfd.setNSize((short) pfd.size()); + pfd.setNSize((short) PIXELFORMATDESCRIPTOR.size()); pfd.setNVersion((short) 1); if(0 != hdc && 1 <= pfdID) { - if (GDI.DescribePixelFormat(hdc, pfdID, pfd.size(), pfd) == 0) { + if (GDI.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { // Accelerated pixel formats that are non displayable if(DEBUG) { System.err.println("Info: Non displayable pixel format " + pfdID + " of device context: error code " + GDI.GetLastError()); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java index 68bdb4ab8..720a1c293 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java @@ -59,7 +59,7 @@ public class X11DummyGLXDrawable extends X11OnscreenGLXDrawable { dummyWindow = X11Util.CreateDummyWindow(dpy, scrn, visualID, f_dim, f_dim); ns.setSurfaceHandle( dummyWindow ); - ns.setSize(f_dim, f_dim); + ns.surfaceSizeChanged(f_dim, f_dim); updateHandle(); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java index eb286cdf0..c3d2530f2 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java @@ -85,7 +85,7 @@ public class X11ExternalGLXDrawable extends X11GLXDrawable { } WrappedSurface ns = new WrappedSurface(cfg); ns.setSurfaceHandle(drawable); - ns.setSize(w, h); + ns.surfaceSizeChanged(w, h); return new X11ExternalGLXDrawable(factory, ns); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java index d2ce629df..d27b9a92b 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java @@ -42,6 +42,7 @@ package jogamp.opengl.x11.glx; import javax.media.nativewindow.*; import javax.media.opengl.*; + import jogamp.opengl.*; public abstract class X11GLXDrawable extends GLDrawableImpl { @@ -64,9 +65,10 @@ public abstract class X11GLXDrawable extends GLDrawableImpl { } } - protected void swapBuffersImpl() { - GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); - } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); + } //--------------------------------------------------------------------------- // Internals only below this point diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 51316dc77..d040775ed 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -423,7 +423,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { WrappedSurface ns = new WrappedSurface( X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen) ); if(ns != null) { - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); } return ns; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java index 8ef642322..8cea2a550 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java @@ -56,14 +56,16 @@ public class X11OnscreenGLXDrawable extends X11GLXDrawable { } @SuppressWarnings("unused") + @Override public long getHandle() { if(USE_GLXWINDOW && useGLXWindow) { return glXWindow; } - return getNativeSurface().getSurfaceHandle(); + return super.getHandle(); } @SuppressWarnings("unused") + @Override protected void destroyHandle() { if(USE_GLXWINDOW && 0!=glXWindow) { GLX.glXDestroyWindow(getNativeSurface().getDisplayHandle(), glXWindow); @@ -72,7 +74,7 @@ public class X11OnscreenGLXDrawable extends X11GLXDrawable { } } - /** must be locked already */ + @Override protected void updateHandle() { if(USE_GLXWINDOW) { X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java index 8ea989267..7bfffd091 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java @@ -48,24 +48,24 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { /* GLCapabilities caps, GLCapabilitiesChooser chooser, int width, int height */ - super(factory, target, true); + super(factory, target, false); - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(); + setRealized(true); if (DEBUG) { System.err.println("Created pbuffer " + this); } } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } @@ -73,7 +73,7 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { return new X11PbufferGLXContext(this, shareWith); } - protected void destroyImpl() { + protected void destroyPbuffer() { NativeSurface ns = getNativeSurface(); if (ns.getSurfaceHandle() != 0) { GLX.glXDestroyPbuffer(ns.getDisplayHandle(), ns.getSurfaceHandle()); @@ -86,7 +86,10 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { AbstractGraphicsScreen aScreen = config.getScreen(); AbstractGraphicsDevice aDevice = aScreen.getDevice(); long display = aDevice.getHandle(); - int screen = aScreen.getIndex(); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); + } if (display==0) { throw new GLException("Null display"); @@ -129,17 +132,11 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { int width = tmp[0]; GLX.glXQueryDrawable(display, pbuffer, GLX.GLX_HEIGHT, tmp, 0); int height = tmp[0]; - ((SurfaceChangeable)ns).setSize(width, height); + ((SurfaceChangeable)ns).surfaceSizeChanged(width, height); } public int getFloatingPointMode() { // Floating-point pbuffers currently require NVidia hardware on X11 return GLPbuffer.NV_FLOAT; } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java index f5d321561..6ede6e13d 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java @@ -48,15 +48,19 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { private long pixmap; protected X11PixmapGLXDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - create(); + super(factory, target, false); + setRealized(true); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - create(); + createPixmap(); } else { - destroyImpl(); + destroyPixmap(); } } @@ -64,7 +68,7 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { return new X11PixmapGLXContext(this, shareWith); } - private void create() { + private void createPixmap() { NativeSurface ns = getNativeSurface(); X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); XVisualInfo vis = config.getXVisualInfo(); @@ -93,7 +97,7 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { } } - protected void destroyImpl() { + protected void destroyPixmap() { if (pixmap == 0) return; NativeSurface ns = getNativeSurface(); @@ -128,10 +132,4 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { ((SurfaceChangeable)ns).setSurfaceHandle(0); display = 0; } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/native/macosx/ContextUpdater.h b/src/jogl/native/macosx/ContextUpdater.h index 3cf7315af..f00b2be57 100644 --- a/src/jogl/native/macosx/ContextUpdater.h +++ b/src/jogl/native/macosx/ContextUpdater.h @@ -25,17 +25,13 @@ This notification is sent whenever an NSView that has an attached NSSurface chan @interface ContextUpdater : NSObject { @protected + pthread_mutex_t resourceLock; NSView * view; NSRect viewRect; NSOpenGLContext *ctx; BOOL viewUpdated; } -- (void) lock; -- (void) lockInFunction:(char *)func atLine:(int)line; -- (void) unlock; -- (void) unlockInFunction:(char *)func atLine:(int)line; - - (id) initWithContext:(NSOpenGLContext *)context view: (NSView *)nsView; - (void) update:(NSNotification *)notification; diff --git a/src/jogl/native/macosx/ContextUpdater.m b/src/jogl/native/macosx/ContextUpdater.m index 21f98ad5e..a3b9b5c8c 100644 --- a/src/jogl/native/macosx/ContextUpdater.m +++ b/src/jogl/native/macosx/ContextUpdater.m @@ -1,43 +1,26 @@ #import "ContextUpdater.h" #import <pthread.h> -@implementation ContextUpdater -{ -} - -static pthread_mutex_t resourceLock = PTHREAD_MUTEX_INITIALIZER; - -static void printLockDebugInfo(char *message, char *func, int line) -{ - fprintf(stderr, "%s in function: \"%s\" at line: %d\n", message, func, line); - fflush(NULL); -} - -- (void) lock -{ - pthread_mutex_lock(&resourceLock); -} +#define VERBOSE_ON 1 -- (void) lockInFunction:(char *)func atLine:(int)line -{ - printLockDebugInfo("locked ", func, line); - [self lock]; -} +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif -- (void) unlock -{ - pthread_mutex_unlock(&resourceLock); -} +#ifndef CGL_VERSION_1_3 + #warning this SDK doesn't support OpenGL profile +#endif -- (void) unlockInFunction:(char *)func atLine:(int)line +@implementation ContextUpdater { - printLockDebugInfo("unlocked", func, line); - [self unlock]; } - (void) update:(NSNotification *)notification { - [self lock]; + pthread_mutex_lock(&resourceLock); NSRect r = [view frame]; if(viewRect.origin.x != r.origin.x || @@ -47,41 +30,47 @@ static void printLockDebugInfo(char *message, char *func, int line) viewUpdated = TRUE; viewRect = r; } - - [self unlock]; + + pthread_mutex_unlock(&resourceLock); } - (BOOL) needsUpdate { BOOL r; - [self lock]; + pthread_mutex_lock(&resourceLock); r = viewUpdated; viewUpdated = FALSE; - [self unlock]; + pthread_mutex_unlock(&resourceLock); return r; } - (id) initWithContext:(NSOpenGLContext *)context view: (NSView *)nsView { + DBG_PRINT("ContextUpdater::init.0 view %p, ctx %p\n", view, ctx); + pthread_mutex_init(&resourceLock, NULL); // fast non-recursive ctx = context; view = nsView; [ctx retain]; [view retain]; viewRect = [view frame]; - viewUpdated = FALSE; + viewUpdated = TRUE; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(update:) name:NSViewGlobalFrameDidChangeNotification object: view]; + DBG_PRINT("ContextUpdater::init.X\n"); return [super init]; } - (void) dealloc { + DBG_PRINT("ContextUpdater::dealloc.0 view %p, ctx %p\n", view, ctx); [[NSNotificationCenter defaultCenter] removeObserver:self]; [view release]; [ctx release]; + pthread_mutex_destroy(&resourceLock); + DBG_PRINT("ContextUpdater::dealloc.X\n"); [super dealloc]; } diff --git a/src/jogl/native/macosx/MacOSXCustomCGLCode.c b/src/jogl/native/macosx/MacOSXCustomCGLCode.c index c29be889d..f8b7a800f 100644 --- a/src/jogl/native/macosx/MacOSXCustomCGLCode.c +++ b/src/jogl/native/macosx/MacOSXCustomCGLCode.c @@ -5,8 +5,7 @@ #include </usr/include/machine/types.h> #include "macosx-window-system.h" -void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { - CGLPixelFormatObj pix = (CGLPixelFormatObj) pixelFormat; +void CGLQueryPixelFormat(CGLPixelFormatObj fmt, int* iattrs, int niattrs, int* ivalues) { // FIXME: think about how specifying this might affect the API int virtualScreen = 0; @@ -14,7 +13,7 @@ void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalu GLint value; for (i = 0; i < niattrs && iattrs[i]>0; i++) { CGLPixelFormatAttribute attr = (CGLPixelFormatAttribute) iattrs[i]; - if ( kCGLNoError == CGLDescribePixelFormat(pix, virtualScreen, attr, &value) ) { + if ( kCGLNoError == CGLDescribePixelFormat(fmt, virtualScreen, attr, &value) ) { ivalues[i] = value; } else { ivalues[i] = 0; diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m new file mode 100644 index 000000000..7233f40ce --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m @@ -0,0 +1,140 @@ + +@interface MyNSOpenGLLayer: NSOpenGLLayer +{ +@protected + NSOpenGLContext* ctxShared; + NSView* view; + NSOpenGLPixelFormat* fmt; +@public + volatile BOOL shallDraw; +} + +- (id) initWithContext: (NSOpenGLContext*) ctx + pixelFormat: (NSOpenGLPixelFormat*) pfmt + view: (NSView*) v + opaque: (Bool) opaque; + +@end + +@implementation MyNSOpenGLLayer + +- (id) initWithContext: (NSOpenGLContext*) _ctx + pixelFormat: (NSOpenGLPixelFormat*) _fmt + view: (NSView*) _view + opaque: (Bool) opaque +{ + self = [super init]; + ctxShared = _ctx; + [ctxShared retain]; + + fmt = _fmt; + [fmt retain]; + + view = _view; + [view retain]; + [self setView: view]; + [view setLayer: self]; + [view setWantsLayer: YES]; + + [self setAsynchronous: NO]; + // [self setAsynchronous: YES]; // FIXME: JAU + [self setNeedsDisplayOnBoundsChange: NO]; + [self setOpaque: opaque ? YES : NO]; + shallDraw = NO; + textureID = 0; + DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, view %p, opaque %d\n", self, ctx, fmt, view, opaque); + return self; +} + +- (void)dealloc +{ + [fmt release]; + [ctxShared release]; + [view release]; + DBG_PRINT("MyNSOpenGLLayer::dealloc %p\n", self); + [super dealloc]; +} + +- (void) setOpenGLContext: (NSOpenGLContext*) _ctx +{ + DBG_PRINT("MyNSOpenGLLayer::setOpenGLContext: %p %p -> %p\n", self, [self openGLContext], _ctx); + [super setOpenGLContext: _ctx]; +} + +- (void) setOpenGLPixelFormat: (NSOpenGLPixelFormat*) _fmt +{ + DBG_PRINT("MyNSOpenGLLayer::setOpenGLPixelFormat %p %p -> %p\n", self, fmt, _fmt); + [super setOpenGLPixelFormat: fmt]; +} + +- (NSOpenGLPixelFormat *) openGLPixelFormat +{ + return fmt; +} + +- (void) setView: (NSView*) v +{ + DBG_PRINT("MyNSOpenGLLayer::setView %p %p -> %p (ignored/propagated)\n", self, view, v); + [super setView: view]; // propagate +} + +- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask +{ + DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask %p %d -> %p\n", self, mask, fmt); + return fmt; +} + +- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat +{ + NSOpenGLContext* ctx = NULL; + if(NULL == ctx) { + int viewNotReady[] = { 0 }; + ctx = createContext(ctxShared, view, true, fmt, [self isOpaque], viewNotReady); + } + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat %p, fmt %p/%p, view %p, shared %p -> %p\n", + self, fmt, pixelFormat, view, ctxShared, ctx); + return ctx; +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + DBG_PRINT("MyNSOpenGLLayer::canDrawInOpenGLContext %p: %d\n", self, self->shallDraw); + return self->shallDraw; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + self->shallDraw = NO; + + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p\n", self, context, pixelFormat); + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSView* view, Bool opaque) { + return [[MyNSOpenGLLayer alloc] initWithContext:ctx pixelFormat: fmt view: view opaque: opaque]; +} + +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + l->shallDraw = YES; + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:YES]; + // NSView* view = [l view]; + // [view setNeedsDisplay: YES]; // FIXME: JAU + // [view performSelectorOnMainThread:@selector(setNeedsDisplay:) withObject:YES waitUntilDone:YES]; + // [view performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:YES]; + DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* l) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [l release]; + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m new file mode 100644 index 000000000..47f679fac --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m @@ -0,0 +1,466 @@ +#import "MacOSXWindowSystemInterface.h" +#import <QuartzCore/QuartzCore.h> +#import <pthread.h> +#include "timespec.h" + +// +// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient. +// Use CVDisplayLink otherwise. +// +// #define HAS_CADisplayLink 1 +// + +// lock/sync debug output +// +// #define DBG_SYNC 1 +// +#ifdef DBG_SYNC + // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define SYNC_PRINT(...) +#endif + +// fps debug output +// +// #define DBG_PERF 1 + +@interface MyNSOpenGLLayer: NSOpenGLLayer +{ +@protected + NSOpenGLPixelBuffer* pbuffer; + int texWidth; + int texHeight; + GLuint textureID; + GLint swapInterval; +#ifdef HAS_CADisplayLink + CADisplayLink* displayLink; +#else + CVDisplayLinkRef displayLink; +#endif + int tc; + struct timespec t0; +@public + pthread_mutex_t renderLock; + pthread_cond_t renderSignal; + BOOL shallDraw; +} + +- (id) setupWithContext: (NSOpenGLContext*) ctx + pixelFormat: (NSOpenGLPixelFormat*) pfmt + pbuffer: (NSOpenGLPixelBuffer*) p + opaque: (Bool) opaque + texWidth: (int) texWidth + texHeight: (int) texHeight; + +- (void)deallocTex; +- (void)disableAnimation; +- (int)getSwapInterval; +- (void)setSwapInterval:(int)interval; +- (void)tick; + +@end + +#ifndef HAS_CADisplayLink + +static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext; + pthread_mutex_lock(&l->renderLock); + #ifdef DBG_PERF + [l tick]; + #endif + pthread_cond_signal(&l->renderSignal); + SYNC_PRINT("-*-"); + pthread_mutex_unlock(&l->renderLock); + [pool release]; + return kCVReturnSuccess; +} + +#endif + +@implementation MyNSOpenGLLayer + +- (id) setupWithContext: (NSOpenGLContext*) _ctx + pixelFormat: (NSOpenGLPixelFormat*) _fmt + pbuffer: (NSOpenGLPixelBuffer*) p + opaque: (Bool) opaque + texWidth: (int) _texWidth + texHeight: (int) _texHeight; +{ + pthread_mutex_init(&renderLock, NULL); // fast non-recursive + pthread_cond_init(&renderSignal, NULL); // no attribute + + pbuffer = p; + [pbuffer retain]; + + // instantiate a deactivated displayLink +#ifdef HAS_CADisplayLink + displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain]; + [displayLink setPaused: YES]; +#else + CVReturn cvres; + { + int allDisplaysMask = 0; + int virtualScreen, accelerated, displayMask; + for (virtualScreen = 0; virtualScreen < [_fmt numberOfVirtualScreens]; virtualScreen++) { + [_fmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen]; + [_fmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen]; + if (accelerated) { + allDisplaysMask |= displayMask; + } + } + cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [_ctx CGLContextObj], [_fmt CGLPixelFormatObj]); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + CVDisplayLinkStop(displayLink); + } +#endif + [self setAsynchronous: YES]; + + [self setNeedsDisplayOnBoundsChange: YES]; // FIXME: learn how to recreate on size change! + [self setOpaque: opaque ? YES : NO]; + texWidth = _texWidth; + texHeight = _texHeight; + textureID = 0; + swapInterval = -1; + shallDraw = NO; + + CGRect lRect = [self frame]; + + DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, frame: %lf/%lf %lfx%lf (refcnt %d)\n", + self, _ctx, _fmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]); + return self; +} + +- (void)disableAnimation +{ + DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); + pthread_mutex_lock(&renderLock); + [self setAsynchronous: NO]; + if(NULL != displayLink) { +#ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + [displayLink release]; +#else + if(NULL!=displayLink) { + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); + } +#endif + displayLink = NULL; + } + pthread_mutex_unlock(&renderLock); +} + +- (void)deallocTex +{ + pthread_mutex_lock(&renderLock); + NSOpenGLContext* context = [self openGLContext]; + DBG_PRINT("MyNSOpenGLLayer::deallocTex %p (refcnt %d) - context %p, pbuffer %p\n", self, (int)[self retainCount], context, pbuffer); + if(NULL != pbuffer) { + if(NULL!=context) { + [context makeCurrentContext]; + if(0 != textureID) { + glDeleteTextures(1, &textureID); + textureID = 0; + } + [context clearDrawable]; + } + [pbuffer release]; + pbuffer = NULL; + } + pthread_mutex_unlock(&renderLock); +} + +- (void)dealloc +{ + DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + [self disableAnimation]; + [self deallocTex]; + pthread_cond_destroy(&renderSignal); + pthread_mutex_destroy(&renderLock); + [super dealloc]; + DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + // assume both methods 'canDrawInOpenGLContext' and 'drawInOpenGLContext' + // are called from the same thread subsequently + pthread_mutex_lock(&renderLock); + Bool res = NULL != pbuffer && YES == shallDraw; + if(!res) { + SYNC_PRINT("<0>"); + pthread_mutex_unlock(&renderLock); + } else { + SYNC_PRINT("<"); + } + return res; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + [context makeCurrentContext]; + // FIXME ?? [context update]; + + /** + * v-sync doesn't works w/ NSOpenGLLayer's context .. well :( + * Using CVDisplayLink .. see setSwapInterval() below. + * + if(0 <= swapInterval) { + GLint si; + [context getValues: &si forParameter: NSOpenGLCPSwapInterval]; + if(si != swapInterval) { + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval); + [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + } + } */ + GLenum textureTarget = [pbuffer textureTarget]; + GLfloat tWidth, tHeight; + { + GLsizei pwidth = [pbuffer pixelsWide]; + GLsizei pheight = [pbuffer pixelsHigh]; + tWidth = textureTarget == GL_TEXTURE_2D ? (GLfloat)pwidth /(GLfloat)texWidth : pwidth; + tHeight = textureTarget == GL_TEXTURE_2D ? (GLfloat)pheight/(GLfloat)texHeight : pheight; + } + Bool texCreated = 0 == textureID; + + if(texCreated) { + glGenTextures(1, &textureID); + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p tex %dx%d -> %fx%f 0x%X: creating texID 0x%X\n", + self, context, pixelFormat, texWidth, texHeight, tWidth, tHeight, textureTarget, textureID); + + CGRect lRect = [self frame]; + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p frame0: %lf/%lf %lfx%lf\n", + self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + if(lRect.origin.x<0 || lRect.origin.y<0) { + lRect.origin.x = 0; + lRect.origin.y = 0; + [self setFrame: lRect]; + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p frame*: %lf/%lf %lfx%lf\n", + self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + } + } + + glBindTexture(textureTarget, textureID); + + /** + if(texCreated) { + // proper tex size setup + glTexImage2D(textureTarget, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } */ + + [context setTextureImageToPixelBuffer: pbuffer colorBuffer: GL_FRONT]; + + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glEnable(textureTarget); + + static GLfloat verts[] = { + -1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + 1.0, -1.0 + }; + + GLfloat tex[] = { + 0.0, 0.0, + 0.0, tHeight, + tWidth, tHeight, + tWidth, 0.0 + }; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, verts); + glTexCoordPointer(2, GL_FLOAT, 0, tex); + + glDrawArrays(GL_QUADS, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(textureTarget); + glBindTexture(textureTarget, 0); + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; + shallDraw = NO; + if(0 >= swapInterval) { + pthread_cond_signal(&renderSignal); + SYNC_PRINT("*"); + } + SYNC_PRINT("1>"); + pthread_mutex_unlock(&renderLock); +} + +- (int)getSwapInterval +{ + return swapInterval; +} + +- (void)setSwapInterval:(int)interval +{ + DBG_PRINT("MyNSOpenGLLayer::setSwapInterval: %d\n", interval); + swapInterval = interval; + if(0 < swapInterval) { + tc = 0; + timespec_now(&t0); + + [self setAsynchronous: NO]; + #ifdef HAS_CADisplayLink + [displayLink setPaused: NO]; + [displayLink setFrameInterval: interval]; + #else + if(NULL!=displayLink) { + CVDisplayLinkStart(displayLink); + // FIXME: doesn't support interval .. + } + #endif + } else { + #ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + #else + if(NULL!=displayLink) { + CVDisplayLinkStop(displayLink); + } + #endif + [self setAsynchronous: YES]; + } +} + +-(void)tick +{ + tc++; + if(tc%60==0) { + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &t0); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n", + td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms ); + fflush(NULL); + } +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, Bool opaque, int texWidth, int texHeight) { + // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ? + // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO. + // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; + + return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; +} + +void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + pthread_mutex_lock(&l->renderLock); + [l setSwapInterval: interval]; + pthread_mutex_unlock(&l->renderLock); +} + +void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + BOOL ready = NO; + int wr = 0; + pthread_mutex_lock(&l->renderLock); + SYNC_PRINT("{"); + do { + if([l getSwapInterval] <= 0) { + ready = !l->shallDraw; + } + if(NO == ready) { + if(0 < to_ms) { + struct timespec to_abs; + timespec_now(&to_abs); + timespec_addms(&to_abs, to_ms); + wr = pthread_cond_timedwait(&l->renderSignal, &l->renderLock, &to_abs); + #ifdef DBG_SYNC + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &to_abs); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "%ld ms", td_ms); + #endif + } else { + pthread_cond_wait (&l->renderSignal, &l->renderLock); + } + ready = !l->shallDraw; + } + } while (NO == ready && 0 == wr) ; + SYNC_PRINT("-%d}", ready); + pthread_mutex_unlock(&l->renderLock); +} + +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + @synchronized(l) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + pthread_mutex_lock(&l->renderLock); + SYNC_PRINT("["); + l->shallDraw = YES; + if([l getSwapInterval] > 0) { + // only trigger update if async mode is off (swapInterval>0) + if ( [NSThread isMainThread] == YES ) { + [l setNeedsDisplay]; + } else { + // can't wait, otherwise we may deadlock AWT + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; + } + SYNC_PRINT("1]"); + } else { + SYNC_PRINT("0]"); + } + pthread_mutex_unlock(&l->renderLock); + // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; + } +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p (refcnt %d)\n", l, (int)[l retainCount]); + + [l performSelectorOnMainThread:@selector(disableAnimation) withObject:nil waitUntilDone:YES]; + // [l disableAnimation]; + + [l performSelectorOnMainThread:@selector(deallocTex) withObject:nil waitUntilDone:YES]; + // [l deallocTex]; + + [l release]; + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p (refcnt %d)\n", l, (int)[l retainCount]); + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.h b/src/jogl/native/macosx/MacOSXWindowSystemInterface.h new file mode 100644 index 000000000..b2d7f9db8 --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.h @@ -0,0 +1,20 @@ +#import <Cocoa/Cocoa.h> +#import <OpenGL/gl.h> +#import <OpenGL/CGLTypes.h> +#import <jni.h> + +#define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +#ifndef CGL_VERSION_1_3 + #warning this SDK doesn't support OpenGL profile +#endif + +#import "macosx-window-system.h" + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m index 751fba9c0..af269a4b5 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m @@ -14,19 +14,10 @@ #endif */ -#import <Cocoa/Cocoa.h> -#import <OpenGL/gl.h> -#import <OpenGL/CGLTypes.h> -#import <jni.h> - -#ifndef CGL_VERSION_1_3 - #warning this SDK doesn't support OpenGL profile -#endif +#import "MacOSXWindowSystemInterface.h" #import "ContextUpdater.h" -#import "macosx-window-system.h" - // see MacOSXPbufferGLContext.java createPbuffer #define USE_GL_TEXTURE_RECTANGLE_EXT @@ -377,7 +368,7 @@ long validateParameter(NSOpenGLPixelFormatAttribute attribute, long value) return value; } -void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { +NSOpenGLPixelFormat* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; getRendererInfo(); @@ -390,6 +381,18 @@ void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { for (i = 0; i < niattrs && iattrs[i]>0; i++) { int attr = iattrs[i]; switch (attr) { + case NSOpenGLPFANoRecovery: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFANoRecovery; + } + break; + + case NSOpenGLPFAAccelerated: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFAAccelerated; + } + break; + case NSOpenGLPFAPixelBuffer: if (ivalues[i] != 0) { attribs[idx++] = NSOpenGLPFAPixelBuffer; @@ -451,9 +454,8 @@ void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { return fmt; } -void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { +void queryPixelFormat(NSOpenGLPixelFormat* fmt, int* iattrs, int niattrs, int* ivalues) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; GLint tmp; // FIXME: think about how specifying this might affect the API GLint virtualScreen = 0; @@ -468,16 +470,43 @@ void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) [pool release]; } -void deletePixelFormat(void* pixelFormat) { +void deletePixelFormat(NSOpenGLPixelFormat* fmt) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; [fmt release]; [pool release]; } -void* createContext(void* shareContext, - void* view, - void* pixelFormat, +NSOpenGLContext* getCurrentContext() { + NSOpenGLContext *ctx = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + ctx = [NSOpenGLContext currentContext]; + [pool release]; + return ctx; +} + +CGLContextObj getCGLContext(NSOpenGLContext* ctx) { + void * cglContext = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + cglContext = [ctx CGLContextObj]; + [pool release]; + return cglContext; +} + +NSView* getNSView(NSOpenGLContext* ctx) { + NSView* view = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + view = [ctx view]; + [pool release]; + return view; +} + +NSOpenGLContext* createContext(NSOpenGLContext* share, + NSView* view, + Bool isBackingLayerView, + NSOpenGLPixelFormat* fmt, Bool opaque, int* viewNotReady) { @@ -485,27 +514,22 @@ void* createContext(void* shareContext, NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSView *nsView = NULL; - NSObject *nsObj = (NSObject*) view; - - if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) { - nsView = (NSView*)nsObj; - } - - if (nsView != NULL) - { + if (view != NULL) { Bool viewReady = true; - if ([nsView lockFocusIfCanDraw] == NO) - { - viewReady = false; + if(!isBackingLayerView) { + if ([view lockFocusIfCanDraw] == NO) { + DBG_PRINT("createContext [view lockFocusIfCanDraw] failed\n"); + viewReady = false; + } } - else - { - NSRect frame = [nsView frame]; - if ((frame.size.width == 0) || (frame.size.height == 0)) - { - [nsView unlockFocus]; + if(viewReady) { + NSRect frame = [view frame]; + if ((frame.size.width == 0) || (frame.size.height == 0)) { + if(!isBackingLayerView) { + [view unlockFocus]; + } + DBG_PRINT("createContext view.frame size %dx%d\n", (int)frame.size.width, (int)frame.size.height); viewReady = false; } } @@ -523,126 +547,80 @@ void* createContext(void* shareContext, } } - NSOpenGLContext* nsContext = [[NSOpenGLContext alloc] - initWithFormat: (NSOpenGLPixelFormat*) pixelFormat - shareContext: (NSOpenGLContext*) shareContext]; + NSOpenGLContext* ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:share]; - if (nsContext != nil) { - if (nsView != nil) { - if(!opaque) { - GLint zeroOpacity = 0; - [nsContext setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; - } - [nsContext setView:nsView]; - [nsView unlockFocus]; - } + if (ctx != nil) { + if (view != nil) { + if(!opaque) { + GLint zeroOpacity = 0; + [ctx setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; + } + [ctx setView:view]; + if(!isBackingLayerView) { + [view unlockFocus]; } + } + } [pool release]; - return nsContext; -} - -void * getCurrentContext() { - NSOpenGLContext *nsContext = NULL; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - nsContext = [NSOpenGLContext currentContext]; - [pool release]; - return nsContext;; -} - -void * getCGLContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - void * cglContext = NULL; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - cglContext = [nsContext CGLContextObj]; - [pool release]; - return cglContext; + return ctx; } -void * getNSView(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - void * view = NULL; - +Bool makeCurrentContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - view = [nsContext view]; - [pool release]; - return view; -} - -Bool makeCurrentContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext makeCurrentContext]; + [ctx makeCurrentContext]; [pool release]; return true; } -Bool clearCurrentContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool clearCurrentContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLContext *currentNSContext = [NSOpenGLContext currentContext]; - if( currentNSContext != nsContext ) { - [nsContext makeCurrentContext]; + if( currentNSContext != ctx ) { + [ctx makeCurrentContext]; } [NSOpenGLContext clearCurrentContext]; [pool release]; return true; } -Bool deleteContext(void* nsJContext, Bool releaseOnMainThread) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool deleteContext(NSOpenGLContext* ctx, Bool releaseOnMainThread) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext clearDrawable]; + [ctx clearDrawable]; if(releaseOnMainThread && NO == [NSThread isMainThread]) { - [nsContext performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES]; + [ctx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES]; } else { // would hangs for ~10s for 1 of a shared context set or offscreen context, set releaseOnMainThread=true ! - [nsContext release]; + [ctx release]; } [pool release]; return true; } -Bool flushBuffer(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool flushBuffer(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext flushBuffer]; + [ctx flushBuffer]; [pool release]; return true; } -void setContextOpacity(void* nsJContext, int opacity) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - - [nsContext setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; +void setContextOpacity(NSOpenGLContext* ctx, int opacity) { + [ctx setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; } -void updateContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +void updateContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext update]; + [ctx update]; [pool release]; } -void copyContext(void* destContext, void* srcContext, int mask) { - NSOpenGLContext *src = (NSOpenGLContext*) srcContext; - NSOpenGLContext *dst = (NSOpenGLContext*) destContext; - [dst copyAttributesFromContext: src withMask: mask]; +void copyContext(NSOpenGLContext* dest, NSOpenGLContext* src, int mask) { + [dest copyAttributesFromContext: src withMask: mask]; } -void* updateContextRegister(void* nsJContext, void* nsJView) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSView *nsView = (NSView*)nsJView; - +void* updateContextRegister(NSOpenGLContext* ctx, NSView* view) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: nsContext view: nsView]; + ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: ctx view: view]; [pool release]; return contextUpdater; } @@ -666,7 +644,7 @@ void updateContextUnregister(void* updater) { [pool release]; } -void* createPBuffer(int renderTarget, int internalFormat, int width, int height) { +NSOpenGLPixelBuffer* createPBuffer(int renderTarget, int internalFormat, int width, int height) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLPixelBuffer* pBuffer = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:renderTarget @@ -678,35 +656,25 @@ void* createPBuffer(int renderTarget, int internalFormat, int width, int height) return pBuffer; } -Bool destroyPBuffer(void* buffer) { - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +Bool destroyPBuffer(NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [pBuffer release]; [pool release]; - return true; } -void setContextPBuffer(void* nsJContext, void* buffer) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +void setContextPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext setPixelBuffer: pBuffer + [ctx setPixelBuffer: pBuffer cubeMapFace: 0 mipMapLevel: 0 - currentVirtualScreen: [nsContext currentVirtualScreen]]; + currentVirtualScreen: [ctx currentVirtualScreen]]; [pool release]; } -void setContextTextureImageToPBuffer(void* nsJContext, void* buffer, int colorBuffer) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer, GLenum colorBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext setTextureImageToPixelBuffer: pBuffer - colorBuffer: (unsigned long) colorBuffer]; + [ctx setTextureImageToPixelBuffer: pBuffer colorBuffer: colorBuffer]; [pool release]; } @@ -746,10 +714,9 @@ void* getProcAddress(const char *procname) { return NULL; } -void setSwapInterval(void* nsJContext, int interval) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; +void setSwapInterval(NSOpenGLContext* ctx, int interval) { GLint swapInterval = interval; - [nsContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + [ctx setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; } Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp) { diff --git a/src/jogl/native/timespec.c b/src/jogl/native/timespec.c new file mode 100644 index 000000000..74c1a6901 --- /dev/null +++ b/src/jogl/native/timespec.c @@ -0,0 +1,63 @@ +#include "timespec.h" +#include <sys/time.h> + +void timespec_now(struct timespec *ts) +{ + struct timeval tv; + + // not using clock_gettime() [of rt library] due to portability + gettimeofday(&tv, NULL); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec*1000; +} + +void timespec_addms(struct timespec *ts, long ms) +{ + int sec=ms/1000; + ms=ms-sec*1000; + + // perform the addition + ts->tv_nsec+=ms*1000000; + + // adjust the time + ts->tv_sec+=ts->tv_nsec/1000000000 + sec; + ts->tv_nsec=ts->tv_nsec%1000000000; +} + +void timespec_addns(struct timespec *ts, long ns) +{ + int sec=ns/1000000000; + ns=ns - sec*1000000000; + + // perform the addition + ts->tv_nsec+=ns; + + // adjust the time + ts->tv_sec+=ts->tv_nsec/1000000000 + sec; + ts->tv_nsec=ts->tv_nsec%1000000000; + +} + +int timespec_compare(struct timespec *a, struct timespec *b) +{ + if (a->tv_sec!=b->tv_sec) + return a->tv_sec-b->tv_sec; + return a->tv_nsec-b->tv_nsec; +} + +void timespec_subtract(struct timespec *r, struct timespec *a, struct timespec *b) +{ + r->tv_sec = a->tv_sec; + r->tv_nsec = a->tv_nsec - b->tv_nsec; + if (r->tv_nsec < 0) { + // borrow. + r->tv_nsec += 1000000000; + r->tv_sec --; + } + r->tv_sec = r->tv_sec - b->tv_sec; +} + +long timespec_milliseconds(struct timespec *a) +{ + return a->tv_sec*1000 + a->tv_nsec/1000000; +} diff --git a/src/jogl/native/timespec.h b/src/jogl/native/timespec.h new file mode 100644 index 000000000..671eb4716 --- /dev/null +++ b/src/jogl/native/timespec.h @@ -0,0 +1,19 @@ +#ifndef _timespec_h +#define _timespec_h + +#include <time.h> + +void timespec_now(struct timespec *ts); +void timespec_addms(struct timespec *ts, long ms); +void timespec_addns(struct timespec *ts, long ns); + +/** returns 0: a==b, >0: a>b, <0: a<b */ +int timespec_compare(struct timespec *a, struct timespec *b); + +/** computes r = a - b */ +void timespec_subtract(struct timespec *r, struct timespec *a, struct timespec *b); + +/** convert the timespec into milliseconds (may overflow) */ +long timespec_milliseconds(struct timespec *a); + +#endif /* _timespec_h */ 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/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index fa3923dcf..e510c0b78 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -60,9 +60,9 @@ 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(); @@ -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..b2a2bc4ee 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> * diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index 76ac72953..e3ee85cf4 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -126,4 +126,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..b6c850098 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, @@ -470,4 +475,33 @@ 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 a {@link OffscreenLayerSurface} is found. + * </p> + * + * @param surface The surface to query. + * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerSurface#isOffscreenLayerSurfaceEnabled()}. + * @return + */ + public static OffscreenLayerSurface getOffscreenLayerSurface(NativeSurface surface, boolean ifEnabled) { + if(surface instanceof OffscreenLayerSurface) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) surface; + return ( !ifEnabled || ols.isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + if(surface instanceof NativeWindow) { + NativeWindow nw = ((NativeWindow) surface).getParent(); + while(null != nw) { + if(nw instanceof OffscreenLayerSurface) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) nw; + return ( !ifEnabled || ols.isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + nw = nw.getParent(); + } + } + return null; + } } 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..82ae0f39e --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -0,0 +1,51 @@ +/** + * 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 { + /** Returns true if this instance uses an offscreen layer, otherwise false. */ + public boolean isOffscreenLayerSurfaceEnabled(); + + /** + * 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..7380d19b6 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java @@ -28,6 +28,8 @@ package javax.media.nativewindow; +import jogamp.nativewindow.SurfaceUpdatedHelper; + import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; @@ -38,6 +40,7 @@ public abstract class ProxySurface implements NativeSurface { protected int height; protected int scrnIndex; protected int width; + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); public ProxySurface(AbstractGraphicsConfiguration cfg) { invalidate(); @@ -73,7 +76,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,9 +85,22 @@ 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 ? @@ -143,5 +159,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..38ad2d795 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java @@ -41,6 +41,7 @@ package javax.media.nativewindow.awt; import javax.media.nativewindow.*; + import java.awt.Component; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; @@ -98,12 +99,42 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple if(null==capsChosen) { GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); - capsChosen = setupCapabilitiesRGBABits(capsChosen, gc); + capsChosen = setupCapabilitiesRGBABits(capsRequested, gc); } return new AWTGraphicsConfiguration(awtScreen, capsChosen, capsRequested, awtGfxConfig); } - @Override + public void updateGraphicsConfiguration(Component awtComp) + { + 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); + } + } + if(null==awtScreen) { + throw new NativeWindowException("native peer n/a: "+awtComp); + } + config = awtGfxConfig; + setScreen(awtScreen); + + CapabilitiesImmutable caps = ( null != getChosenCapabilities() ) ? getChosenCapabilities() : getRequestedCapabilities(); + GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); + setChosenCapabilities(setupCapabilitiesRGBABits(caps, gc)); + } + + // open access to superclass method + public void setChosenCapabilities(CapabilitiesImmutable capsChosen) { + super.setChosenCapabilities(capsChosen); + } + + @Override public Object clone() { return super.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..9869e1eb3 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java @@ -32,8 +32,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 +43,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/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/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index d34d4e58f..5cb7d5aca 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -32,11 +32,16 @@ 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.NativeSurface; +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 +49,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 +71,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..65ecc48fe 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) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index c1c97eece..ddf453bab 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -42,6 +42,8 @@ import java.awt.EventQueue; import javax.media.nativewindow.*; +import com.jogamp.common.os.Platform; + import java.awt.GraphicsEnvironment; import java.awt.Toolkit; @@ -55,6 +57,7 @@ public class JAWTUtil { // 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 +78,63 @@ 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(); 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 +164,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 +224,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 +232,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtLock failed", e); } } else { - JAWT.getJAWT().Lock(); + jawtLockObject.Lock(); } } @@ -207,7 +242,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 +250,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..0f97b0b9f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java @@ -42,48 +42,101 @@ import com.jogamp.common.util.locks.RecursiveLock; import java.awt.Component; import java.awt.Window; +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.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 { protected static final boolean DEBUG = JAWTUtil.DEBUG; + // user properties + protected boolean shallUseOffscreenLayer = false; + // lifetime: forever protected Component component; - protected AbstractGraphicsConfiguration config; + protected AWTGraphicsConfiguration config; + 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) { + /** + * 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"); + } + this.config = (AWTGraphicsConfiguration) config; init((Component)comp); } private void init(Component windowObject) throws NativeWindowException { invalidate(); this.component = windowObject; + this.isApplet = false; validateNative(); } + + /** + * Request an JAWT offscreen layer if supported. + * Shall be called before {@link #lockSurface()}. + * + * @see #getShallUseOffscreenLayer() + * @see #isOffscreenLayerSurfaceEnabled() + */ + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + /** Returns the property set by {@link #setShallUseOffscreenLayer(boolean)}. */ + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + /** + * Implementors shall ensure that all native handles are valid, eg. the {@link javax.media.nativewindow.awt.AWTGraphicsDevice AWTGraphicsDevice}'s + * subtype via {@link javax.media.nativewindow.awt.AWTGraphicsDevice#setSubType(String, long) awtGraphicsDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle)}. + * <p> + * This method may be called several times, + * hence the implementation shall check for valid values 1st and bail out early if satisfied. + * </p> + * @throws NativeWindowException + */ protected abstract void validateNative() throws NativeWindowException; protected synchronized void invalidate() { - component = null; + invalidateNative(); + jawt = null; + isOffscreenLayerSurface = false; drawable= 0; bounds = new Rectangle(); } + protected abstract void invalidateNative(); protected final void updateBounds(JAWT_Rectangle jawtBounds) { bounds.setX(jawtBounds.getX()); @@ -100,14 +153,91 @@ public abstract class JAWTWindow implements NativeWindow { 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} + * @see #setShallUseOffscreenLayer(boolean) + */ + public final boolean isOffscreenLayerSurfaceEnabled() { + return isOffscreenLayerSurface; + } + + /** + * {@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,17 +245,39 @@ 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 { + validateNative(); surfaceLock.lock(); 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(); adevice.lock(); try { + jawt = fetchJAWTImpl(); + isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); res = lockSurfaceImpl(); } finally { if (LOCK_SURFACE_NOT_READY >= res) { @@ -169,15 +321,14 @@ 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() { return config; } @@ -190,15 +341,11 @@ public abstract class JAWTWindow implements NativeWindow { return config.getScreen().getIndex(); } - public final void setSize(int width, int height) { - component.setSize(width, height); - } - - public final int getWidth() { + public int getWidth() { return component.getWidth(); } - public final int getHeight() { + public int getHeight() { return component.getHeight(); } @@ -207,12 +354,13 @@ public abstract class JAWTWindow implements NativeWindow { // public synchronized void destroy() { + invalidate(); if(null!=component) { if(component instanceof Window) { ((Window)component).dispose(); } + component = null; } - invalidate(); } public final NativeWindow getParent() { @@ -222,7 +370,7 @@ public abstract class JAWTWindow implements NativeWindow { public long getWindowHandle() { return drawable; } - + public final int getX() { return component.getX(); } @@ -230,44 +378,85 @@ 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); - + + public boolean hasFocus() { + return component.hasFocus(); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index d4f6a95d4..70fc1d62f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -41,37 +41,96 @@ 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.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 +146,83 @@ 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) config.getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + config.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); + } else { + System.err.println("JAWT n/a, bounds "+bounds); } - // 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/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 982b94888..adb9353ce 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -47,6 +47,7 @@ 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; @@ -61,15 +62,24 @@ public class WindowsJAWTWindow extends JAWTWindow { 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 +104,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 +115,11 @@ 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; if(null!=ds) { if (null!=dsi) { ds.FreeDrawingSurfaceInfo(dsi); @@ -119,7 +127,7 @@ public class WindowsJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; @@ -131,7 +139,7 @@ public class WindowsJAWTWindow extends JAWTWindow { return windowHandle; } - protected Point getLocationOnScreenImpl(int x, int y) { + protected Point getLocationOnScreenNativeImpl(int x, int y) { return GDI.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 2319d6269..236d380d8 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -48,6 +48,7 @@ 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; @@ -60,7 +61,7 @@ public class X11JAWTWindow extends JAWTWindow { } protected void validateNative() throws NativeWindowException { - AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); + final AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); if(awtDevice.getHandle() != 0) { // subtype and handle set already, done @@ -85,10 +86,23 @@ public class X11JAWTWindow extends JAWTWindow { } awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); } + + protected void invalidateNative() { } + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + protected void detachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + + 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 +127,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 +137,6 @@ public class X11JAWTWindow extends JAWTWindow { if (drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } @@ -136,14 +149,14 @@ 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) { + protected Point getLocationOnScreenNativeImpl(int x, int y) { return X11Util.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java index b576b0c6b..6dbf36612 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; } @@ -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..a93ab2ac1 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -1,5 +1,7 @@ package jogamp.nativewindow.macosx; +import java.nio.Buffer; + import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; @@ -34,6 +36,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 +86,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/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index b669bce75..910e564af 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -33,8 +33,14 @@ 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 { protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index e19d5ecf7..d7a2feff3 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,182 @@ 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]]; + + // force surface creation + // [myView lockFocus]; + // [myView unlockFocus]; + + [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); + NSView* mView = [mWin contentView]; + + if(NULL!=mView) { + [mWin setContentView: nil]; + [mView release]; + } + [mWin orderOut: mWin]; + [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]; + + // 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]; + // simple 1:1 layout ! + [subLayer setFrame:lRectRoot]; + DBG_PRINT("CALayer::AddCASublayer0.0: %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:^(){ + [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 +401,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/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index d3be098c0..f38876128 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -34,14 +34,19 @@ package com.jogamp.newt; -import javax.media.nativewindow.*; - -import com.jogamp.common.os.Platform; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; +import jogamp.newt.Debug; import jogamp.newt.DisplayImpl; import jogamp.newt.ScreenImpl; import jogamp.newt.WindowImpl; -import jogamp.newt.Debug; + +import com.jogamp.common.os.Platform; public class NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); @@ -141,35 +146,34 @@ public class NewtFactory { * * @param parentWindowObject either a NativeWindow instance */ - public static Window createWindow(NativeWindow nParentWindow, CapabilitiesImmutable caps) { + public static Window createWindow(NativeWindow parentWindow, CapabilitiesImmutable caps) { final String type = NativeWindowFactory.getNativeWindowType(true); - Screen screen = null; - Window parentWindow = null; + Window newtParentWindow = null; - if ( nParentWindow instanceof Window ) { + if ( parentWindow instanceof Window ) { // use parent NEWT Windows Display/Screen - parentWindow = (Window) nParentWindow ; - screen = parentWindow.getScreen(); + newtParentWindow = (Window) parentWindow ; + screen = newtParentWindow.getScreen(); } else { // create a Display/Screen compatible to the NativeWindow - AbstractGraphicsConfiguration nParentConfig = nParentWindow.getGraphicsConfiguration(); - if(null!=nParentConfig) { - AbstractGraphicsScreen nParentScreen = nParentConfig.getScreen(); - AbstractGraphicsDevice nParentDevice = nParentScreen.getDevice(); - Display display = NewtFactory.createDisplay(type, nParentDevice.getHandle(), true); - screen = NewtFactory.createScreen(display, nParentScreen.getIndex()); + AbstractGraphicsConfiguration parentConfig = parentWindow.getGraphicsConfiguration(); + if(null!=parentConfig) { + AbstractGraphicsScreen parentScreen = parentConfig.getScreen(); + AbstractGraphicsDevice parentDevice = parentScreen.getDevice(); + Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true); + screen = NewtFactory.createScreen(display, parentScreen.getIndex()); } else { Display display = NewtFactory.createDisplay(type, null, true); // local display screen = NewtFactory.createScreen(display, 0); // screen 0 } } - final Window win = createWindowImpl(nParentWindow, screen, caps); + final Window win = createWindowImpl(parentWindow, screen, caps); - win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); - if ( null != parentWindow ) { - parentWindow.addChild(win); - win.setVisible(parentWindow.isVisible()); + win.setSize(parentWindow.getWidth(), parentWindow.getHeight()); + if ( null != newtParentWindow ) { + newtParentWindow.addChild(win); + win.setVisible(newtParentWindow.isVisible()); } return win; } diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index a78f81668..32024a49a 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -30,12 +30,13 @@ package com.jogamp.newt; import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.MouseListener; import jogamp.newt.Debug; import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeWindow; -import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.WindowClosingProtocol; /** @@ -133,6 +134,11 @@ public interface Window extends NativeWindow, WindowClosingProtocol { boolean isVisible(); + /** + * If the implementation uses delegation, return the delegated {@link Window} instance, + * otherwise return <code>this</code> instance. */ + Window getDelegatedWindow(); + // // Child Window Management // @@ -310,16 +316,46 @@ public interface Window extends NativeWindow, WindowClosingProtocol { } /** - * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. + * Sets a {@link FocusRunnable}, + * which {@link FocusRunnable#run()} method is executed before the native focus is requested. + * <p> * This allows notifying a covered window toolkit like AWT that the focus is requested, * hence focus traversal can be made transparent. + * </p> */ void setFocusAction(FocusRunnable focusAction); + + /** + * Sets a {@link KeyListener} allowing focus traversal with a covered window toolkit like AWT. + * <p> + * The {@link KeyListener} methods are invoked prior to all other {@link KeyListener}'s + * allowing to suppress the {@link KeyEvent} via the {@link InputEvent#consumedTag}. + * </p> + * @param l + */ + void setKeyboardFocusHandler(KeyListener l); + /** + * Request focus for this native window + * <p> + * The request is handled on this Window EDT and blocked until finished. + * </p> + * + * @see #requestFocus(boolean) + */ void requestFocus(); - boolean hasFocus(); - + /** + * Request focus for this native window + * <p> + * The request is handled on this Window EDT. + * </p> + * + * @param wait true if waiting until the request is executed, otherwise false + * @see #requestFocus() + */ + void requestFocus(boolean wait); + void windowRepaint(int x, int y, int width, int height); void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event); @@ -328,38 +364,6 @@ public interface Window extends NativeWindow, WindowClosingProtocol { // - // SurfaceUpdateListener - // - - /** - * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of - * the list. - */ - void addSurfaceUpdatedListener(SurfaceUpdatedListener l); - - /** - * - * Inserts the given {@link com.jogamp.newt.event.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 - */ - void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; - - void removeAllSurfaceUpdatedListener(); - - void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); - - SurfaceUpdatedListener getSurfaceUpdatedListener(int index); - - SurfaceUpdatedListener[] getSurfaceUpdatedListeners(); - - - // // WindowListener // diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 31d42d21b..f56a95537 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -29,42 +29,56 @@ package com.jogamp.newt.awt; -import com.jogamp.newt.Display; -import java.lang.reflect.*; -import java.security.*; - +import java.awt.AWTKeyStroke; import java.awt.Canvas; -import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.KeyboardFocusManager; - +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Set; + +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeWindow; -import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.awt.AWTWindowClosingProtocol; +import javax.swing.MenuSelectionManager; + import jogamp.nativewindow.awt.AWTMisc; +import jogamp.nativewindow.jawt.JAWTWindow; +import jogamp.newt.Debug; +import jogamp.newt.awt.NewtFactoryAWT; +import jogamp.newt.awt.event.AWTParentWindowAdapter; +import jogamp.newt.driver.DriverClearFocus; -import com.jogamp.newt.event.awt.AWTAdapter; -import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.Display; import com.jogamp.newt.Window; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowListener; -import jogamp.newt.Debug; -import jogamp.newt.awt.event.AWTParentWindowAdapter; -import jogamp.newt.awt.event.NewtFactoryAWT; - -import javax.swing.MenuSelectionManager; +import com.jogamp.newt.event.awt.AWTAdapter; +import com.jogamp.newt.event.awt.AWTKeyAdapter; +import com.jogamp.newt.event.awt.AWTMouseAdapter; @SuppressWarnings("serial") public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol { public static final boolean DEBUG = Debug.debug("Window"); - NativeWindow nativeWindow = null; - Window newtChild = null; - int newtChildCloseOp; - AWTAdapter awtAdapter = null; - + private JAWTWindow jawtWindow = null; + private Window newtChild = null; + private boolean isOnscreen = true; + private int newtChildCloseOp; + private AWTAdapter awtAdapter = null; + private AWTAdapter awtMouseAdapter = null; + private AWTAdapter awtKeyAdapter = null; + private AWTWindowClosingProtocol awtWindowClosingProtocol = new AWTWindowClosingProtocol(this, new Runnable() { public void run() { @@ -77,6 +91,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto */ public NewtCanvasAWT() { super(); + createNativeWindow(new Capabilities()); } /** @@ -84,6 +99,23 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto */ public NewtCanvasAWT(GraphicsConfiguration gc) { super(gc); + createNativeWindow(new Capabilities()); + } + + /** + * Instantiates a NewtCanvas without a NEWT child.<br> + */ + public NewtCanvasAWT(CapabilitiesImmutable caps) { + super(); + createNativeWindow(caps); + } + + /** + * Instantiates a NewtCanvas without a NEWT child.<br> + */ + public NewtCanvasAWT(GraphicsConfiguration gc, CapabilitiesImmutable caps) { + super(gc); + createNativeWindow(caps); } /** @@ -91,6 +123,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto */ public NewtCanvasAWT(Window child) { super(); + createNativeWindow(child.getRequestedCapabilities()); setNEWTChild(child); } @@ -99,56 +132,154 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto */ public NewtCanvasAWT(GraphicsConfiguration gc, Window child) { super(gc); + createNativeWindow(child.getRequestedCapabilities()); setNEWTChild(child); } + private final void createNativeWindow(CapabilitiesImmutable caps) { + jawtWindow = NewtFactoryAWT.getNativeWindow(this, caps); + } + + /** + * Request an JAWT offscreen layer if supported it. + * Shall be called before {@link #addNotify()} is issued, + * ie. before adding the component to the AWT tree and make it visible. + * + * @see #isOffscreenLayerSurface() + */ + public void setShallUseOffscreenLayer(boolean v) { + jawtWindow.setShallUseOffscreenLayer(v); + } + + /** + * Returns true if the underlying JAWT uses offscreen layering, + * otherwise false. This information is valid only after {@link #addNotify()} is issued, + * ie. before adding the component to the AWT tree and make it visible. + * + * @see #setShallUseOffscreenLayer(boolean) + */ + public boolean isOffscreenLayerSurface() { + return jawtWindow.isOffscreenLayerSurfaceEnabled(); + } + + /** + * Returns true if the AWT component is parented to an {@link java.applet.Applet}, + * otherwise false. This information is valid only after {@link #addNotify()} is issued, + * ie. before adding the component to the AWT tree and make it visible. + */ + public boolean isApplet() { + return jawtWindow.isApplet(); + } + class FocusAction implements Window.FocusRunnable { public boolean run() { - if ( EventQueue.isDispatchThread() ) { - focusActionImpl.run(); - } else { - try { - EventQueue.invokeAndWait(focusActionImpl); - } catch (Exception e) { - throw new NativeWindowException(e); - } - /** - // wait for AWT focus ! - for(long sleep = Window.TIMEOUT_NATIVEWINDOW; 0<sleep && !isFocusOwner(); sleep-=10 ) { - try { Thread.sleep(10); } catch (InterruptedException e) { } - } */ + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusAction: "+Display.getThreadName()+", isOnscreen "+isOnscreen+", hasFocus "+hasFocus()); } - return focusActionImpl.result; - } - - class FocusActionImpl implements Runnable { - public final boolean result = false; // NEWT shall always proceed requesting the native focus - public void run() { - if(DEBUG) { - System.err.println("FocusActionImpl.run() "+Display.getThreadName()); - } - NewtCanvasAWT.this.requestFocusAWTParent(); + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + if(!hasFocus()) { + // Acquire the AWT focus 1st for proper AWT traversal + NewtCanvasAWT.super.requestFocus(); + } + if(isOnscreen) { + // Remove the AWT focus in favor of the native NEWT focus KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); } + return false; // NEWT shall proceed requesting the native focus } - FocusActionImpl focusActionImpl = new FocusActionImpl(); } - FocusAction focusAction = new FocusAction(); + private FocusAction focusAction = new FocusAction(); WindowListener clearAWTMenusOnNewtFocus = new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent arg0) { - MenuSelectionManager.defaultManager().clearSelectedPath(); + MenuSelectionManager.defaultManager().clearSelectedPath(); } }; - /** sets a new NEWT child, provoking reparenting on the NEWT level. */ - /*package */ NewtCanvasAWT setNEWTChild(Window child) { + class FocusTraversalKeyListener implements KeyListener { + boolean suppress = false; + + public void keyPressed(KeyEvent e) { + handleKey(e, false); + } + public void keyReleased(KeyEvent e) { + handleKey(e, true); + } + public void keyTyped(KeyEvent e) { + if(suppress) { + e.setAttachment(InputEvent.consumedTag); + suppress = false; // reset + } + } + + void handleKey(KeyEvent evt, boolean onRelease) { + if(null == keyboardFocusManager) { + throw new InternalError("XXX"); + } + final AWTKeyStroke ks = AWTKeyStroke.getAWTKeyStroke(evt.getKeyCode(), evt.getModifiers(), onRelease); + if(null != ks) { + final Set<AWTKeyStroke> fwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + final Set<AWTKeyStroke> bwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + if(fwdKeys.contains(ks)) { + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey (fwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()); + } + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + NewtCanvasAWT.this.transferFocus(); + suppress = true; + } else if(bwdKeys.contains(ks)) { + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey (bwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()); + } + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + NewtCanvasAWT.this.transferFocusBackward(); + suppress = true; + } + } + if(suppress) { + evt.setAttachment(InputEvent.consumedTag); + } + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey: XXX: "+ks); + } + } + } + private final FocusTraversalKeyListener newtFocusTraversalKeyListener = new FocusTraversalKeyListener(); + + class FocusPropertyChangeListener implements PropertyChangeListener { + public void propertyChange(PropertyChangeEvent evt) { + final Object oldF = evt.getOldValue(); + final Object newF = evt.getNewValue(); + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: "+evt.getPropertyName()+", src "+evt.getSource()+", "+oldF+" -> "+newF); + } + if(oldF == NewtCanvasAWT.this && newF == null) { + // focus traversal to NEWT - NOP + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: NEWT focus traversal"); + } + } else if(null != newF && newF != NewtCanvasAWT.this) { + // focus traversal to another AWT component + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: lost focus - clear focus"); + } + if(newtChild.getDelegatedWindow() instanceof DriverClearFocus) { + ((DriverClearFocus)newtChild.getDelegatedWindow()).clearFocus(); + } + } + } + } + private final FocusPropertyChangeListener focusPropertyChangeListener = new FocusPropertyChangeListener(); + private volatile KeyboardFocusManager keyboardFocusManager = null; + + /** sets a new NEWT child, provoking reparenting. */ + private NewtCanvasAWT setNEWTChild(Window child) { if(newtChild!=child) { newtChild = child; - if(null!=nativeWindow) { - java.awt.Container cont = AWTMisc.getContainer(this); + if(isDisplayable()) { // reparent right away, addNotify has been called already + final java.awt.Container cont = AWTMisc.getContainer(this); reparentWindow( (null!=child) ? true : false, cont ); } } @@ -162,8 +293,8 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto /** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called, * or {@link #addNotify()} hasn't been called yet.*/ - public NativeWindow getNativeWindow() { return nativeWindow; } - + public NativeWindow getNativeWindow() { return jawtWindow; } + public int getDefaultCloseOperation() { return awtWindowClosingProtocol.getDefaultCloseOperation(); } @@ -177,13 +308,41 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto awtAdapter.removeFrom(this); awtAdapter=null; } + if(null!=awtMouseAdapter) { + awtMouseAdapter.removeFrom(this); + awtMouseAdapter = null; + } + if(null!=awtKeyAdapter) { + awtKeyAdapter.removeFrom(this); + awtKeyAdapter = null; + } + newtChild.setKeyboardFocusHandler(null); + if(null != keyboardFocusManager) { + keyboardFocusManager.removePropertyChangeListener("focusOwner", focusPropertyChangeListener); + keyboardFocusManager = null; + } + if( null != newtChild ) { if(attach) { + if(null == jawtWindow.getGraphicsConfiguration()) { + throw new InternalError("XXX"); + } + isOnscreen = jawtWindow.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this); newtChild.addWindowListener(clearAWTMenusOnNewtFocus); newtChild.setFocusAction(focusAction); // enable AWT focus traversal newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingProtocol.DO_NOTHING_ON_CLOSE); awtWindowClosingProtocol.addClosingListenerOneShot(); + keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + keyboardFocusManager.addPropertyChangeListener("focusOwner", focusPropertyChangeListener); + if(isOnscreen) { + // onscreen newt child needs to fwd AWT focus + newtChild.setKeyboardFocusHandler(newtFocusTraversalKeyListener); + } else { + // offscreen newt child requires AWT to fwd AWT key/mouse event + awtMouseAdapter = new AWTMouseAdapter(newtChild).addTo(this); + awtKeyAdapter = new AWTKeyAdapter(newtChild).addTo(this); + } } else { newtChild.removeWindowListener(clearAWTMenusOnNewtFocus); newtChild.setFocusAction(null); @@ -232,24 +391,40 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto newtChild.setFocusAction(null); // no AWT focus traversal .. if(add) { - nativeWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); - if(null!=nativeWindow) { - if(DEBUG) { - System.err.println("NewtCanvasAWT.reparentWindow: "+newtChild); - } - final int w = cont.getWidth(); - final int h = cont.getHeight(); - setSize(w, h); - newtChild.setSize(w, h); - newtChild.reparentWindow(nativeWindow); - newtChild.setVisible(true); - configureNewtChild(true); - newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener - newtChild.windowRepaint(0, 0, w, h); + NewtFactoryAWT.updateGraphicsConfiguration(jawtWindow, this); + if(DEBUG) { + System.err.println("NewtCanvasAWT.reparentWindow: "+newtChild); } + final int w; + final int h; + if(isPreferredSizeSet()) { + java.awt.Dimension d = getPreferredSize(); + w = d.width; + h = d.height; + } else { + final java.awt.Dimension min; + if(this.isMinimumSizeSet()) { + min = getMinimumSize(); + } else { + min = new java.awt.Dimension(0, 0); + } + java.awt.Insets ins = cont.getInsets(); + w = Math.max(min.width, cont.getWidth() - ins.left - ins.right); + h = Math.max(min.height, cont.getHeight() - ins.top - ins.bottom); + } + setSize(w, h); + newtChild.setSize(w, h); + newtChild.reparentWindow(jawtWindow); + newtChild.setVisible(true); + configureNewtChild(true); + newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener + newtChild.windowRepaint(0, 0, w, h); + + // force this AWT Canvas to be focus-able, + // since this it is completely covered by the newtChild (z-order). + setFocusable(true); } else { configureNewtChild(false); - nativeWindow = null; newtChild.setVisible(false); newtChild.reparentWindow(null); } @@ -273,7 +448,10 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto System.err.println("NewtCanvasAWT.destroy(): "+newtChild+", from "+cont); } configureNewtChild(false); - nativeWindow = null; + if(null!=jawtWindow) { + jawtWindow.destroy(); + jawtWindow=null; + } newtChild.setVisible(false); newtChild.reparentWindow(null); newtChild.destroy(); @@ -299,14 +477,12 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } } - final void requestFocusAWTParent() { - super.requestFocusInWindow(); - } - - final void requestFocusNEWTChild() { + private final void requestFocusNEWTChild() { if(null!=newtChild) { newtChild.setFocusAction(null); - KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + if(isOnscreen) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + } newtChild.requestFocus(); newtChild.setFocusAction(focusAction); } diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java index 2e86cb512..7ba892b37 100755 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java @@ -1,20 +1,50 @@ +/** + * 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 com.jogamp.newt.awt.applet; -import java.applet.*; +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Button; import java.awt.Component; import java.awt.Container; -import java.awt.Label; +import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; -import java.awt.event.KeyListener; -import javax.media.opengl.*; +import javax.media.opengl.FPSCounter; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLProfile; + +import jogamp.newt.Debug; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; -import java.awt.BorderLayout; - -import jogamp.newt.Debug; /** * Simple GLEventListener deployment as an applet using JOGL. This demo must be @@ -62,7 +92,7 @@ import jogamp.newt.Debug; */ @SuppressWarnings("serial") public class JOGLNewtApplet1Run extends Applet { - public static final boolean DEBUG = Debug.debug("Applet"); + public static final boolean DEBUG = JOGLNewtAppletBase.DEBUG; GLWindow glWindow; NewtCanvasAWT newtCanvasAWT; @@ -72,6 +102,9 @@ public class JOGLNewtApplet1Run extends Applet { boolean glStandalone = false; public void init() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.init() START"); + } if(!(this instanceof Container)) { throw new RuntimeException("This Applet is not a AWT Container"); } @@ -88,6 +121,7 @@ public class JOGLNewtApplet1Run extends Applet { int glAlphaBits=0; int glNumMultisampleBuffer=0; boolean glNoDefaultKeyListener = false; + boolean appletDebugTestBorder = false; try { glEventListenerClazzName = getParameter("gl_event_listener_class"); glProfileName = getParameter("gl_profile"); @@ -104,6 +138,7 @@ public class JOGLNewtApplet1Run extends Applet { glWidth = JOGLNewtAppletBase.str2Int(getParameter("gl_width"), glWidth); glHeight = JOGLNewtAppletBase.str2Int(getParameter("gl_height"), glHeight); glNoDefaultKeyListener = JOGLNewtAppletBase.str2Bool(getParameter("gl_nodefaultkeyListener"), glNoDefaultKeyListener); + appletDebugTestBorder = JOGLNewtAppletBase.str2Bool(getParameter("appletDebugTestBorder"), appletDebugTestBorder); } catch (Exception e) { e.printStackTrace(); } @@ -149,18 +184,19 @@ public class JOGLNewtApplet1Run extends Applet { glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err); glWindow.setUndecorated(glUndecorated); glWindow.setAlwaysOnTop(glAlwaysOnTop); + container.setLayout(new BorderLayout()); + if(appletDebugTestBorder) { + container.add(new Button("North"), BorderLayout.NORTH); + container.add(new Button("South"), BorderLayout.SOUTH); + container.add(new Button("East"), BorderLayout.EAST); + container.add(new Button("West"), BorderLayout.WEST); + } if(glStandalone) { newtCanvasAWT = null; } else { newtCanvasAWT = new NewtCanvasAWT(glWindow); - container.setLayout(new BorderLayout()); container.add(newtCanvasAWT, BorderLayout.CENTER); - } - if(DEBUG) { - container.add(new Label("North"), BorderLayout.NORTH); - container.add(new Label("South"), BorderLayout.SOUTH); - container.add(new Label("East"), BorderLayout.EAST); - container.add(new Label("West"), BorderLayout.WEST); + container.validate(); } base.init(glWindow); if(base.isValid()) { @@ -179,9 +215,15 @@ public class JOGLNewtApplet1Run extends Applet { } catch (Throwable t) { throw new RuntimeException(t); } + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.init() END"); + } } public void start() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.start() START"); + } this.validate(); this.setVisible(true); @@ -195,21 +237,35 @@ public class JOGLNewtApplet1Run extends Applet { while (null != topC.getParent()) { topC = topC.getParent(); } + System.err.println("JOGLNewtApplet1Run start:"); System.err.println("TopComponent: "+topC.getLocation()+" rel, "+topC.getLocationOnScreen()+" screen, visible "+topC.isVisible()+", "+topC); System.err.println("Applet Pos: "+this.getLocation()+" rel, "+p0+" screen, visible "+this.isVisible()+", "+this); if(null != newtCanvasAWT) { System.err.println("NewtCanvasAWT Pos: "+newtCanvasAWT.getLocation()+" rel, "+newtCanvasAWT.getLocationOnScreen()+" screen, visible "+newtCanvasAWT.isVisible()+", "+newtCanvasAWT); } System.err.println("GLWindow Pos: "+glWindow.getX()+"/"+glWindow.getY()+" rel, "+glWindow.getLocationOnScreen(null)+" screen"); + System.err.println("GLWindow: "+glWindow); } base.start(); + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.stop() END"); + } } public void stop() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.stop() START"); + } base.stop(); + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.stop() END"); + } } public void destroy() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.destroy() START"); + } glWindow.setVisible(false); // hide 1st if(!glStandalone) { glWindow.reparentWindow(null); // get out of newtCanvasAWT @@ -217,6 +273,9 @@ public class JOGLNewtApplet1Run extends Applet { } base.destroy(); // destroy glWindow unrecoverable base=null; + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.destroy() END"); + } } } diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java index b1061dd14..6b135976b 100755 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java @@ -1,18 +1,52 @@ +/** + * 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 com.jogamp.newt.awt.applet; -import java.lang.reflect.*; +import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.NativeWindow; -import javax.media.opengl.*; +import javax.media.opengl.FPSCounter; +import javax.media.opengl.GL; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLPipelineFactory; import jogamp.newt.Debug; -import com.jogamp.opengl.util.*; - -import com.jogamp.newt.event.*; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + /** Shows how to deploy an applet using JOGL. This demo must be referenced from a web page via an <applet> tag. */ diff --git a/src/newt/classes/com/jogamp/newt/event/InputEvent.java b/src/newt/classes/com/jogamp/newt/event/InputEvent.java index 51ceccf31..d8a9235c1 100644 --- a/src/newt/classes/com/jogamp/newt/event/InputEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/InputEvent.java @@ -48,6 +48,11 @@ public abstract class InputEvent extends NEWTEvent public static final int CONFINED_MASK = 1 << 16; public static final int INVISIBLE_MASK = 1 << 17; + /** Object when attached via {@link #setAttachment(Object)} marks the event consumed, + * ie. stops propagating the event any further to the event listener. + */ + public static final Object consumedTag = new Object(); + protected InputEvent(int eventType, Object source, long when, int modifiers) { super(eventType, source, when); this.modifiers=modifiers; diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java index 9e4fe372b..44fcea49c 100644 --- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java @@ -34,6 +34,7 @@ package com.jogamp.newt.event; +@SuppressWarnings("serial") public class KeyEvent extends InputEvent { public KeyEvent(int eventType, Object source, long when, int modifiers, int keyCode, char keyChar) { @@ -42,9 +43,12 @@ public class KeyEvent extends InputEvent this.keyChar=keyChar; } + /** Only valid if delivered via {@link KeyListener#keyPressed(KeyEvent)} */ public char getKeyChar() { return keyChar; } + + /** Always valid. */ public int getKeyCode() { return keyCode; } diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java index 50aed2c8e..3f3817b91 100644 --- a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java @@ -46,6 +46,7 @@ package com.jogamp.newt.event; * <li> KeyEvent <code>300..30x</code></li> * </ul><br> */ +@SuppressWarnings("serial") public class NEWTEvent extends java.util.EventObject { private final boolean isSystemEvent; private final int eventType; diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 2cd8c2ced..166718423 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -41,6 +41,7 @@ import com.jogamp.common.GlueGenVersion; import com.jogamp.common.util.VersionUtil; import com.jogamp.newt.*; import com.jogamp.newt.event.*; + import jogamp.newt.WindowImpl; import javax.media.nativewindow.*; @@ -54,8 +55,8 @@ import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.util.Animator; /** - * An implementation of {@link javax.media.opengl.GLAutoDrawable} interface, - * using an aggregation of a {@link com.jogamp.newt.Window} implementation. + * An implementation of {@link GLAutoDrawable} and {@link Window} interface, + * using a delegated {@link Window} instance, which may be an aggregation (lifecycle: created and destroyed). * <P> * This implementation does not make the OpenGL context current<br> * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br> @@ -195,8 +196,8 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC return window.getRequestedCapabilities(); } - public final Window getWindow() { - return window; + public final Window getDelegatedWindow() { + return window.getDelegatedWindow(); } public final NativeWindow getParent() { @@ -254,10 +255,18 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC window.setFocusAction(focusAction); } + public void setKeyboardFocusHandler(KeyListener l) { + window.setKeyboardFocusHandler(l); + } + public final void requestFocus() { window.requestFocus(); } + public final void requestFocus(boolean wait) { + window.requestFocus(wait); + } + public boolean hasFocus() { return window.hasFocus(); } @@ -753,18 +762,6 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC window.runOnEDTIfAvail(wait, task); } - public final SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - return window.getSurfaceUpdatedListener(index); - } - - public final SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - return window.getSurfaceUpdatedListeners(); - } - - public final void removeAllSurfaceUpdatedListener() { - window.removeAllSurfaceUpdatedListener(); - } - public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { window.removeSurfaceUpdatedListener(l); } diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java index fa7bafe5b..e923c37a9 100644 --- a/src/newt/classes/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java @@ -48,9 +48,6 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { static long nextWindowHandle = 0x100; // start here - a marker protected void createNativeImpl() { - if(0!=getParentWindowHandle()) { - throw new NativeWindowException("OffscreenWindow does not support window parenting"); - } if(capsRequested.isOnscreen()) { throw new NativeWindowException("Capabilities is onscreen"); } @@ -70,6 +67,10 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { // nop } + public void surfaceSizeChanged(int width, int height) { + sizeChanged(false, width, height, false); + } + @Override public synchronized void destroy() { super.destroy(); @@ -89,29 +90,30 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { } @Override - public void setSize(int width, int height) { - if(!isVisible()) { - sizeChanged(false, width, height, false); - } - } - @Override public void setPosition(int x, int y) { // nop } + @Override public boolean setFullscreen(boolean fullscreen) { // nop return false; } - + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { sizeChanged(false, width, height, false); - visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags)); + visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags)); } else { - shouldNotCallThis(); + /** + * silently ignore: + FLAG_CHANGE_PARENTING + FLAG_CHANGE_DECORATION + FLAG_CHANGE_FULLSCREEN + FLAG_CHANGE_ALWAYSONTOP + */ } - return false; + return true; } @Override diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index 9c51fe973..252be7cfd 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -208,6 +208,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { public synchronized final int addReference() throws NativeWindowException { if(DEBUG) { System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); + // Thread.dumpStack(); } if ( 0 == refCount ) { createNative(); @@ -220,10 +221,8 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { public synchronized final int removeReference() { if(DEBUG) { - String msg = "Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1); - // Throwable t = new Throwable(msg); - // t.printStackTrace(); - System.err.println(msg); + System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + // Thread.dumpStack(); } refCount--; // could become < 0, in case of manual destruction without actual creation/addReference if(0>=refCount) { diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 7df326e8e..f4856bafe 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -72,6 +72,8 @@ import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; +import jogamp.nativewindow.SurfaceUpdatedHelper; + public abstract class WindowImpl implements Window, NEWTEventConsumer { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); @@ -108,10 +110,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private RequestFocusAction requestFocusAction = new RequestFocusAction(); private FocusRunnable focusAction = null; + private KeyListener keyboardFocusHandler = null; - private Object surfaceUpdatedListenersLock = new Object(); - private ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); - + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); + private Object childWindowsLock = new Object(); private ArrayList<NativeWindow> childWindows = new ArrayList<NativeWindow>(); @@ -682,6 +684,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return screen; } + protected final void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, visible)); + } final void setVisibleActionImpl(boolean visible) { boolean nativeWindowCreated = false; boolean madeVisible = false; @@ -740,8 +745,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( nativeWindowCreated || madeVisible ) { sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener } - } - + } private class VisibleAction implements Runnable { boolean visible; @@ -752,8 +756,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public final void run() { setVisibleActionImpl(visible); } - } - + } public void setVisible(boolean visible) { if(DEBUG_IMPLEMENTATION) { System.err.println("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+(null!=parentWindow)); @@ -762,59 +765,67 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer runOnEDTIfAvail(true, new VisibleAction(visible)); } - protected final void setVisibleImpl(boolean visible, int x, int y, int width, int height) { - reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, visible)); + final void setSizeActionImpl(int width, int height) { + boolean recreate = false; + windowLock.lock(); + try { + int visibleAction = 0; // 1 invisible, 2 visible (create) + if ( !fullscreen && ( width != WindowImpl.this.width || WindowImpl.this.height != height ) ) { + recreate = isNativeValid() && !getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: START "+WindowImpl.this.width+"x"+WindowImpl.this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible+", recreate "+recreate); + } + if(recreate) { + // will trigger visibleAction:=2 -> create if wasVisible + final boolean wasVisible = WindowImpl.this.visible; + screen.addReference(); // retain screen + destroyAction.run(); + WindowImpl.this.visible = wasVisible; + } + if ( isNativeValid() && 0>=width*height && visible ) { + visibleAction=1; // invisible + WindowImpl.this.width = 0; + WindowImpl.this.height = 0; + } else if ( !isNativeValid() && 0<width*height && visible ) { + visibleAction = 2; // visible (create) + WindowImpl.this.width = width; + WindowImpl.this.height = height; + } else if ( isNativeValid() ) { + // this width/height will be set by windowChanged, called by the native implementation + reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(0, isVisible())); + } else { + WindowImpl.this.width = width; + WindowImpl.this.height = height; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: END "+WindowImpl.this.width+"x"+WindowImpl.this.height+", visibleAction "+visibleAction); + } + switch(visibleAction) { + case 1: setVisibleActionImpl(false); break; + case 2: setVisibleActionImpl(true); break; + } + } + } finally { + if(recreate) { + screen.removeReference(); // bring back ref-count + } + windowLock.unlock(); + } } - - private class SetSizeActionImpl implements Runnable { + private class SetSizeAction implements Runnable { int width, height; - private SetSizeActionImpl(int w, int h) { + private SetSizeAction(int w, int h) { width = w; height = h; } public final void run() { - windowLock.lock(); - try { - int visibleAction = 0; // 1 invisible, 2 visible (create) - if ( !fullscreen && ( width != WindowImpl.this.width || WindowImpl.this.height != height ) ) { - if(DEBUG_IMPLEMENTATION) { - String msg = "Window setSize: START "+WindowImpl.this.width+"x"+WindowImpl.this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible; - System.err.println(msg); - } - if ( isNativeValid() && 0>=width*height && visible ) { - visibleAction=1; // invisible - WindowImpl.this.width = 0; - WindowImpl.this.height = 0; - } else if ( !isNativeValid() && 0<width*height && visible ) { - visibleAction = 2; // visible (create) - WindowImpl.this.width = width; - WindowImpl.this.height = height; - } else if ( isNativeValid() ) { - // this width/height will be set by windowChanged, called by the native implementation - reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(0, isVisible())); - } else { - WindowImpl.this.width = width; - WindowImpl.this.height = height; - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setSize: END "+WindowImpl.this.width+"x"+WindowImpl.this.height+", visibleAction "+visibleAction); - } - switch(visibleAction) { - case 1: setVisibleActionImpl(false); break; - case 2: setVisibleActionImpl(true); break; - } - } - } finally { - windowLock.unlock(); - } + setSizeActionImpl(width, height); } - } - + } public void setSize(int width, int height) { - runOnEDTIfAvail(true, new SetSizeActionImpl(width, height)); - } - + runOnEDTIfAvail(true, new SetSizeAction(width, height)); + } public void setTopLevelSize(int width, int height) { setSize(width - getInsets().getTotalWidth(), height - getInsets().getTotalHeight()); } @@ -911,6 +922,22 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer runOnEDTIfAvail(true, destroyAction); } + /** + * @param cWin child window, must not be null + * @param pWin parent window, may be null + * @return true if at least one of both window's configurations is offscreen + */ + protected static boolean isOffscreenInstance(NativeWindow cWin, NativeWindow pWin) { + boolean ofs = false; + if( null != cWin.getGraphicsConfiguration() ) { + ofs = !cWin.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); + } + if( !ofs && null != pWin && null != pWin.getGraphicsConfiguration() ) { + ofs |= !pWin.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); + } + return ofs; + } + private class ReparentActionImpl implements Runnable, ReparentAction { NativeWindow newParentWindow; boolean forceDestroyCreate; @@ -918,7 +945,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private ReparentActionImpl(NativeWindow newParentWindow, boolean forceDestroyCreate) { this.newParentWindow = newParentWindow; - this.forceDestroyCreate = forceDestroyCreate; + this.forceDestroyCreate = forceDestroyCreate | DEBUG_TEST_REPARENT_INCOMPATIBLE; this.reparentAction = -1; // ensure it's set } @@ -927,10 +954,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } private void setScreen(ScreenImpl newScreen) { // never null ! - WindowImpl.this.removeScreenReference(); + removeScreenReference(); screen = newScreen; } - + public final void run() { boolean animatorPaused = false; if(null!=lifecycleHook) { @@ -952,6 +979,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer windowLock.lock(); try { + if(isNativeValid()) { + // force recreation if offscreen, since it may become onscreen + forceDestroyCreate |= isOffscreenInstance(WindowImpl.this, newParentWindow); + } + wasVisible = isVisible(); Window newParentWindowNEWT = null; @@ -962,7 +994,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer long newParentWindowHandle = 0 ; if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.reparent: START ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCodeNullSafe(parentWindow)+", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", DEBUG_TEST_REPARENT_INCOMPATIBLE "+DEBUG_TEST_REPARENT_INCOMPATIBLE+" "+x+"/"+y+" "+width+"x"+height); + System.err.println("Window.reparent: START ("+getThreadName()+") valid "+isNativeValid()+", windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCodeNullSafe(parentWindow)+", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", "+x+"/"+y+" "+width+"x"+height); } if(null!=lifecycleHook) { @@ -1013,8 +1045,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } else { reparentAction = ACTION_NATIVE_CREATION_PENDING; } - } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate || - !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { + } else if ( forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { // Destroy this window, may create a new compatible Screen/Display, // and mark it for creation. destroy(); @@ -1045,7 +1076,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( 0 == parentWindowHandle ) { // Already Top Window reparentAction = ACTION_UNCHANGED; - } else if( !isNativeValid() || DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate ) { + } else if( !isNativeValid() || forceDestroyCreate ) { // Destroy this window and mark it for [pending] creation. destroy(); if( 0<width*height ) { @@ -1138,7 +1169,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer ok = WindowImpl.this.waitForSize(width, height, false, TIMEOUT_NATIVEWINDOW); } if(ok) { - requestFocusImpl(true); + requestFocusInt(true); display.dispatchMessagesNative(); // status up2date } } @@ -1208,7 +1239,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { - ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); + final ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); runOnEDTIfAvail(true, reparentAction); return reparentAction.getStrategy(); } @@ -1385,14 +1416,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } - public void requestFocus() { - enqueueRequestFocus(true); - } - - public final boolean hasFocus() { - return hasFocus; - } - public final InsetsImmutable getInsets() { if(isUndecorated()) { return Insets.getZero(); @@ -1452,7 +1475,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public Object getWrappedWindow() { return null; } - + + public final Window getDelegatedWindow() { + return this; + } + /** * If set to true, the default value, this NEWT Window implementation will * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.<br> @@ -1487,9 +1514,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer "\n, WrappedWindow "+getWrappedWindow()+ "\n, ChildWindows "+childWindows.size()); - sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); - for (int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { - sb.append(surfaceUpdatedListeners.get(i)+", "); + sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedHelper.size()+" ["); + for (int i = 0; i < surfaceUpdatedHelper.size(); i++ ) { + sb.append(surfaceUpdatedHelper.get(i)+", "); } sb.append("], WindowListeners num "+windowListeners.size()+" ["); for (int i = 0; i < windowListeners.size(); i++ ) { @@ -1529,21 +1556,32 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } - protected void enqueueRequestFocus(boolean wait) { - runOnEDTIfAvail(wait, requestFocusAction); + public final boolean hasFocus() { + return hasFocus; } - /** - * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. - * This allows notifying a covered window toolkit like AWT that the focus is requested, - * hence focus traversal can be made transparent. - */ + public void requestFocus() { + requestFocus(true); + } + + public void requestFocus(boolean wait) { + if(!focusAction()) { + runOnEDTIfAvail(wait, requestFocusAction); + } + } + + /** Internal request focus on current thread */ + private void requestFocusInt(boolean force) { + if(!focusAction()) { + requestFocusImpl(force); + } + } + public void setFocusAction(FocusRunnable focusAction) { this.focusAction = focusAction; } - - /** Called by native requestFocusImpl() */ - protected boolean focusAction() { + + private boolean focusAction() { if(DEBUG_IMPLEMENTATION) { System.err.println("Window.focusAction() START - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle())); } @@ -1558,7 +1596,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } return res; } - + + public void setKeyboardFocusHandler(KeyListener l) { + keyboardFocusHandler = l; + } + private class SetPositionActionImpl implements Runnable { int x, y; @@ -1680,7 +1722,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer display.dispatchMessagesNative(); // status up2date WindowImpl.this.waitForSize(w, h, false, TIMEOUT_NATIVEWINDOW); display.dispatchMessagesNative(); // status up2date - requestFocusImpl(true); + requestFocusInt(true); display.dispatchMessagesNative(); // status up2date if(DEBUG_IMPLEMENTATION) { @@ -1800,8 +1842,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // queue event in case window is locked, ie in operation if( isWindowLocked() ) { if(DEBUG_IMPLEMENTATION) { - // System.err.println("Window.consumeEvent: queued "+e); - // Thread.dumpStack(); // JAU + System.err.println("Window.consumeEvent: queued "+e); + // Thread.dumpStack(); } return false; } @@ -1824,62 +1866,20 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // // SurfaceUpdatedListener Support // - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - addSurfaceUpdatedListener(-1, l); + surfaceUpdatedHelper.addSurfaceUpdatedListener(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 addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); } public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - if (l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners.remove(l); - } - } - - public void removeAllSurfaceUpdatedListener() { - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); - } - } - - public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size()-1; - } - return surfaceUpdatedListeners.get(index); - } - } - - public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - synchronized(surfaceUpdatedListenersLock) { - return (SurfaceUpdatedListener[]) surfaceUpdatedListeners.toArray(); - } + surfaceUpdatedHelper.removeSurfaceUpdatedListener(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); - } - } + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); } // @@ -2033,8 +2033,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(DEBUG_MOUSE_EVENT) { System.err.println("consumeMouseEvent: event: "+e); } - - for(int i = 0; i < mouseListeners.size(); i++ ) { + boolean consumed = false; + for(int i = 0; !consumed && i < mouseListeners.size(); i++ ) { MouseListener l = mouseListeners.get(i); switch(e.getEventType()) { case MouseEvent.EVENT_MOUSE_CLICKED: @@ -2064,13 +2064,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer default: throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); } + consumed = InputEvent.consumedTag == e.getAttachment(); } } // // KeyListener/Event Support // - public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); } @@ -2119,26 +2119,39 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return (KeyListener[]) keyListeners.toArray(); } - protected void consumeKeyEvent(KeyEvent e) { - if(DEBUG_KEY_EVENT) { - System.err.println("consumeKeyEvent: "+e); + private final boolean propagateKeyEvent(KeyEvent e, KeyListener l) { + switch(e.getEventType()) { + case KeyEvent.EVENT_KEY_PRESSED: + l.keyPressed(e); + break; + case KeyEvent.EVENT_KEY_RELEASED: + l.keyReleased(e); + break; + case KeyEvent.EVENT_KEY_TYPED: + l.keyTyped(e); + break; + default: + throw new NativeWindowException("Unexpected key event type " + e.getEventType()); } - for(int i = 0; i < keyListeners.size(); i++ ) { - KeyListener l = keyListeners.get(i); - switch(e.getEventType()) { - case KeyEvent.EVENT_KEY_PRESSED: - l.keyPressed(e); - break; - case KeyEvent.EVENT_KEY_RELEASED: - l.keyReleased(e); - break; - case KeyEvent.EVENT_KEY_TYPED: - l.keyTyped(e); - break; - default: - throw new NativeWindowException("Unexpected key event type " + e.getEventType()); + return InputEvent.consumedTag == e.getAttachment(); + } + + protected void consumeKeyEvent(KeyEvent e) { + boolean consumed; + if(null != keyboardFocusHandler) { + consumed = propagateKeyEvent(e, keyboardFocusHandler); + if(DEBUG_KEY_EVENT) { + System.err.println("consumeKeyEvent: "+e+", keyboardFocusHandler consumed: "+consumed); + } + } else { + consumed = false; + if(DEBUG_KEY_EVENT) { + System.err.println("consumeKeyEvent: "+e); } } + for(int i = 0; !consumed && i < keyListeners.size(); i++ ) { + consumed = propagateKeyEvent(e, keyListeners.get(i)); + } } // diff --git a/src/newt/classes/jogamp/newt/awt/event/NewtFactoryAWT.java b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java index aa98d3a37..d4b2fd3d6 100644 --- a/src/newt/classes/jogamp/newt/awt/event/NewtFactoryAWT.java +++ b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java @@ -27,13 +27,15 @@ */ -package jogamp.newt.awt.event; +package jogamp.newt.awt; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; import com.jogamp.newt.NewtFactory; + +import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.newt.Debug; public class NewtFactoryAWT extends NewtFactory { @@ -51,7 +53,7 @@ public class NewtFactoryAWT extends NewtFactory { * * @param awtCompObject must be of type java.awt.Component */ - public static NativeWindow getNativeWindow(Object awtCompObject, CapabilitiesImmutable capsRequested) { + public static JAWTWindow getNativeWindow(Object awtCompObject, CapabilitiesImmutable capsRequested) { if(null==awtCompObject) { throw new NativeWindowException("Null AWT Component"); } @@ -61,13 +63,34 @@ public class NewtFactoryAWT extends NewtFactory { return getNativeWindow( (java.awt.Component) awtCompObject, capsRequested ); } - public static NativeWindow getNativeWindow(java.awt.Component awtComp, CapabilitiesImmutable capsRequested) { - DefaultGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, capsRequested, capsRequested); - NativeWindow awtNative = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow + public static JAWTWindow getNativeWindow(java.awt.Component awtComp, CapabilitiesImmutable capsRequested) { + AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, null, capsRequested); + NativeWindow nw = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow + if(! ( nw instanceof JAWTWindow ) ) { + throw new NativeWindowException("Not an AWT NativeWindow: "+nw); + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("NewtFactoryAWT.getNativeWindow: "+awtComp+" -> "+nw); + } + return (JAWTWindow)nw; + } + + public static void updateGraphicsConfiguration(JAWTWindow nw, java.awt.Component awtComp) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("NewtFactoryAWT.updateGraphicsConfiguration: (pre) "+awtComp+" -> "+nw); + } + final AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration) nw.getGraphicsConfiguration(); + awtConfig.updateGraphicsConfiguration(awtComp); + // lockSurface() re-issues JAWTWindow's native validation + if( NativeSurface.LOCK_SURFACE_NOT_READY >= nw.lockSurface() ) { + throw new NativeWindowException("could not lock "+nw); + } + nw.unlockSurface(); + if(DEBUG_IMPLEMENTATION) { - System.err.println("NewtFactoryAWT.getNativeWindow: "+awtComp+" -> "+awtNative); + System.err.println("NewtFactoryAWT.updateGraphicsConfiguration: (post) "+awtComp+" -> "+nw); } - return awtNative; } + } diff --git a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java index 358864547..313a5e868 100644 --- a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java +++ b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java @@ -28,6 +28,8 @@ package jogamp.newt.awt.event; +import java.awt.KeyboardFocusManager; + import com.jogamp.newt.event.awt.AWTAdapter; import com.jogamp.newt.event.awt.AWTWindowAdapter; @@ -54,9 +56,16 @@ public class AWTParentWindowAdapter } public void focusGained(java.awt.event.FocusEvent e) { + // forward focus to NEWT child + final com.jogamp.newt.Window newtChild = getNewtWindow(); + final boolean isOnscreen = newtChild.isNativeValid() && newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); if(DEBUG_IMPLEMENTATION) { - System.err.println("AWT: focusGained: "+ e); + System.err.println("AWT: focusGained: onscreen "+ isOnscreen+", "+e); + } + if(isOnscreen) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); } + newtChild.requestFocus(false); } public void focusLost(java.awt.event.FocusEvent e) { diff --git a/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java new file mode 100644 index 000000000..4d23c4ea8 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java @@ -0,0 +1,12 @@ +package jogamp.newt.driver; + +/** + * Interface tagging driver feature / requirement of clearing the focus. + * <p> + * Some drivers require a programmatic {@link #clearFocus()} when traversing the focus. + * </p> + */ +public interface DriverClearFocus { + /** Programmatic clear the focus */ + void clearFocus(); +} diff --git a/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java b/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java index bb678935a..a7326d916 100644 --- a/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java +++ b/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java @@ -30,7 +30,6 @@ package jogamp.newt.driver.android; import javax.media.opengl.GLProfile; import com.jogamp.newt.Window; -import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.util.Animator; import jogamp.newt.driver.android.AndroidWindow; @@ -63,9 +62,7 @@ public class NewtBaseActivity extends Activity { } public void setContentView(android.view.Window androidWindow, Window newtWindow) { - if(newtWindow instanceof GLWindow) { - newtWindow = ((GLWindow)newtWindow).getWindow(); - } + newtWindow = newtWindow.getDelegatedWindow(); if(newtWindow instanceof AndroidWindow) { this.newtWindow = (AndroidWindow)newtWindow; this.newtWindow.setAndroidWindow(androidWindow); diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java new file mode 100644 index 000000000..46625f7a9 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java @@ -0,0 +1,262 @@ +package jogamp.newt.driver.macosx; + +import com.jogamp.newt.event.KeyEvent; + +public class MacKeyUtil { + + // KeyCodes (independent) + private static final int kVK_Return = 0x24; + private static final int kVK_Tab = 0x30; + private static final int kVK_Space = 0x31; + private static final int kVK_Delete = 0x33; + private static final int kVK_Escape = 0x35; + private static final int kVK_Command = 0x37; + private static final int kVK_Shift = 0x38; + private static final int kVK_CapsLock = 0x39; + private static final int kVK_Option = 0x3A; + private static final int kVK_Control = 0x3B; + private static final int kVK_RightShift = 0x3C; + private static final int kVK_RightOption = 0x3D; + private static final int kVK_RightControl = 0x3E; + private static final int kVK_Function = 0x3F; + private static final int kVK_F17 = 0x40; + private static final int kVK_VolumeUp = 0x48; + private static final int kVK_VolumeDown = 0x49; + private static final int kVK_Mute = 0x4A; + private static final int kVK_F18 = 0x4F; + private static final int kVK_F19 = 0x50; + private static final int kVK_F20 = 0x5A; + private static final int kVK_F5 = 0x60; + private static final int kVK_F6 = 0x61; + private static final int kVK_F7 = 0x62; + private static final int kVK_F3 = 0x63; + private static final int kVK_F8 = 0x64; + private static final int kVK_F9 = 0x65; + private static final int kVK_F11 = 0x67; + private static final int kVK_F13 = 0x69; + private static final int kVK_F16 = 0x6A; + private static final int kVK_F14 = 0x6B; + private static final int kVK_F10 = 0x6D; + private static final int kVK_F12 = 0x6F; + private static final int kVK_F15 = 0x71; + private static final int kVK_Help = 0x72; + private static final int kVK_Home = 0x73; + private static final int kVK_PageUp = 0x74; + private static final int kVK_ForwardDelete = 0x75; + private static final int kVK_F4 = 0x76; + private static final int kVK_End = 0x77; + private static final int kVK_F2 = 0x78; + private static final int kVK_PageDown = 0x79; + private static final int kVK_F1 = 0x7A; + private static final int kVK_LeftArrow = 0x7B; + private static final int kVK_RightArrow = 0x7C; + private static final int kVK_DownArrow = 0x7D; + private static final int kVK_UpArrow = 0x7E; + + // Key constants handled differently on Mac OS X than other platforms + private static final char NSUpArrowFunctionKey = 0xF700; + private static final char NSDownArrowFunctionKey = 0xF701; + private static final char NSLeftArrowFunctionKey = 0xF702; + private static final char NSRightArrowFunctionKey = 0xF703; + private static final char NSF1FunctionKey = 0xF704; + private static final char NSF2FunctionKey = 0xF705; + private static final char NSF3FunctionKey = 0xF706; + private static final char NSF4FunctionKey = 0xF707; + private static final char NSF5FunctionKey = 0xF708; + private static final char NSF6FunctionKey = 0xF709; + private static final char NSF7FunctionKey = 0xF70A; + private static final char NSF8FunctionKey = 0xF70B; + private static final char NSF9FunctionKey = 0xF70C; + private static final char NSF10FunctionKey = 0xF70D; + private static final char NSF11FunctionKey = 0xF70E; + private static final char NSF12FunctionKey = 0xF70F; + private static final char NSF13FunctionKey = 0xF710; + private static final char NSF14FunctionKey = 0xF711; + private static final char NSF15FunctionKey = 0xF712; + private static final char NSF16FunctionKey = 0xF713; + private static final char NSF17FunctionKey = 0xF714; + private static final char NSF18FunctionKey = 0xF715; + private static final char NSF19FunctionKey = 0xF716; + private static final char NSF20FunctionKey = 0xF717; + private static final char NSF21FunctionKey = 0xF718; + private static final char NSF22FunctionKey = 0xF719; + private static final char NSF23FunctionKey = 0xF71A; + private static final char NSF24FunctionKey = 0xF71B; + private static final char NSF25FunctionKey = 0xF71C; + private static final char NSF26FunctionKey = 0xF71D; + private static final char NSF27FunctionKey = 0xF71E; + private static final char NSF28FunctionKey = 0xF71F; + private static final char NSF29FunctionKey = 0xF720; + private static final char NSF30FunctionKey = 0xF721; + private static final char NSF31FunctionKey = 0xF722; + private static final char NSF32FunctionKey = 0xF723; + private static final char NSF33FunctionKey = 0xF724; + private static final char NSF34FunctionKey = 0xF725; + private static final char NSF35FunctionKey = 0xF726; + private static final char NSInsertFunctionKey = 0xF727; + private static final char NSDeleteFunctionKey = 0xF728; + private static final char NSHomeFunctionKey = 0xF729; + private static final char NSBeginFunctionKey = 0xF72A; + private static final char NSEndFunctionKey = 0xF72B; + private static final char NSPageUpFunctionKey = 0xF72C; + private static final char NSPageDownFunctionKey = 0xF72D; + private static final char NSPrintScreenFunctionKey = 0xF72E; + private static final char NSScrollLockFunctionKey = 0xF72F; + private static final char NSPauseFunctionKey = 0xF730; + private static final char NSSysReqFunctionKey = 0xF731; + private static final char NSBreakFunctionKey = 0xF732; + private static final char NSResetFunctionKey = 0xF733; + private static final char NSStopFunctionKey = 0xF734; + private static final char NSMenuFunctionKey = 0xF735; + private static final char NSUserFunctionKey = 0xF736; + private static final char NSSystemFunctionKey = 0xF737; + private static final char NSPrintFunctionKey = 0xF738; + private static final char NSClearLineFunctionKey = 0xF739; + private static final char NSClearDisplayFunctionKey = 0xF73A; + private static final char NSInsertLineFunctionKey = 0xF73B; + private static final char NSDeleteLineFunctionKey = 0xF73C; + private static final char NSInsertCharFunctionKey = 0xF73D; + private static final char NSDeleteCharFunctionKey = 0xF73E; + private static final char NSPrevFunctionKey = 0xF73F; + private static final char NSNextFunctionKey = 0xF740; + private static final char NSSelectFunctionKey = 0xF741; + private static final char NSExecuteFunctionKey = 0xF742; + private static final char NSUndoFunctionKey = 0xF743; + private static final char NSRedoFunctionKey = 0xF744; + private static final char NSFindFunctionKey = 0xF745; + private static final char NSHelpFunctionKey = 0xF746; + private static final char NSModeSwitchFunctionKey = 0xF747; + + static int validateKeyCode(int keyCode, char keyChar) { + // OS X Virtual Keycodes + switch(keyCode) { + case kVK_Return: return KeyEvent.VK_ENTER; + case kVK_Tab: return KeyEvent.VK_TAB; + case kVK_Space: return KeyEvent.VK_SPACE; + case kVK_Delete: return KeyEvent.VK_BACK_SPACE; + case kVK_Escape: return KeyEvent.VK_ESCAPE; + case kVK_Command: return KeyEvent.VK_ALT; + case kVK_Shift: return KeyEvent.VK_SHIFT; + case kVK_CapsLock: return KeyEvent.VK_CAPS_LOCK; + case kVK_Option: return KeyEvent.VK_WINDOWS; + case kVK_Control: return KeyEvent.VK_CONTROL; + case kVK_RightShift: return KeyEvent.VK_SHIFT; + case kVK_RightOption: return KeyEvent.VK_WINDOWS; + case kVK_RightControl: return KeyEvent.VK_CONTROL; + // case kVK_Function: return KeyEvent.VK_F; + case kVK_F17: return KeyEvent.VK_F17; + // case kVK_VolumeUp: + // case kVK_VolumeDown: + // case kVK_Mute: + case kVK_F18: return KeyEvent.VK_F18; + case kVK_F19: return KeyEvent.VK_F19; + case kVK_F20: return KeyEvent.VK_F20; + case kVK_F5: return KeyEvent.VK_F5; + case kVK_F6: return KeyEvent.VK_F6; + case kVK_F7: return KeyEvent.VK_F7; + case kVK_F3: return KeyEvent.VK_F3; + case kVK_F8: return KeyEvent.VK_F8; + case kVK_F9: return KeyEvent.VK_F9; + case kVK_F11: return KeyEvent.VK_F11; + case kVK_F13: return KeyEvent.VK_F13; + case kVK_F16: return KeyEvent.VK_F16; + case kVK_F14: return KeyEvent.VK_F14; + case kVK_F10: return KeyEvent.VK_F10; + case kVK_F12: return KeyEvent.VK_F12; + case kVK_F15: return KeyEvent.VK_F15; + case kVK_Help: return KeyEvent.VK_HELP; + case kVK_Home: return KeyEvent.VK_HOME; + case kVK_PageUp: return KeyEvent.VK_PAGE_UP; + case kVK_ForwardDelete: return KeyEvent.VK_DELETE; + case kVK_F4: return KeyEvent.VK_F4; + case kVK_End: return KeyEvent.VK_END; + case kVK_F2: return KeyEvent.VK_F2; + case kVK_PageDown: return KeyEvent.VK_PAGE_DOWN; + case kVK_F1: return KeyEvent.VK_F1; + case kVK_LeftArrow: return KeyEvent.VK_LEFT; + case kVK_RightArrow: return KeyEvent.VK_RIGHT; + case kVK_DownArrow: return KeyEvent.VK_DOWN; + case kVK_UpArrow: return KeyEvent.VK_UP; + } + + if (keyChar == '\r') { + // Turn these into \n + return KeyEvent.VK_ENTER; + } + + if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { + switch (keyChar) { + case NSUpArrowFunctionKey: return KeyEvent.VK_UP; + case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; + case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; + case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; + case NSF1FunctionKey: return KeyEvent.VK_F1; + case NSF2FunctionKey: return KeyEvent.VK_F2; + case NSF3FunctionKey: return KeyEvent.VK_F3; + case NSF4FunctionKey: return KeyEvent.VK_F4; + case NSF5FunctionKey: return KeyEvent.VK_F5; + case NSF6FunctionKey: return KeyEvent.VK_F6; + case NSF7FunctionKey: return KeyEvent.VK_F7; + case NSF8FunctionKey: return KeyEvent.VK_F8; + case NSF9FunctionKey: return KeyEvent.VK_F9; + case NSF10FunctionKey: return KeyEvent.VK_F10; + case NSF11FunctionKey: return KeyEvent.VK_F11; + case NSF12FunctionKey: return KeyEvent.VK_F12; + case NSF13FunctionKey: return KeyEvent.VK_F13; + case NSF14FunctionKey: return KeyEvent.VK_F14; + case NSF15FunctionKey: return KeyEvent.VK_F15; + case NSF16FunctionKey: return KeyEvent.VK_F16; + case NSF17FunctionKey: return KeyEvent.VK_F17; + case NSF18FunctionKey: return KeyEvent.VK_F18; + case NSF19FunctionKey: return KeyEvent.VK_F19; + case NSF20FunctionKey: return KeyEvent.VK_F20; + case NSF21FunctionKey: return KeyEvent.VK_F21; + case NSF22FunctionKey: return KeyEvent.VK_F22; + case NSF23FunctionKey: return KeyEvent.VK_F23; + case NSF24FunctionKey: return KeyEvent.VK_F24; + case NSInsertFunctionKey: return KeyEvent.VK_INSERT; + case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; + case NSHomeFunctionKey: return KeyEvent.VK_HOME; + case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; + case NSEndFunctionKey: return KeyEvent.VK_END; + case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; + case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; + case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; + case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; + case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; + // Not handled: + // NSSysReqFunctionKey + // NSBreakFunctionKey + // NSResetFunctionKey + case NSStopFunctionKey: return KeyEvent.VK_STOP; + // Not handled: + // NSMenuFunctionKey + // NSUserFunctionKey + // NSSystemFunctionKey + // NSPrintFunctionKey + // NSClearLineFunctionKey + // NSClearDisplayFunctionKey + // NSInsertLineFunctionKey + // NSDeleteLineFunctionKey + // NSInsertCharFunctionKey + // NSDeleteCharFunctionKey + // NSPrevFunctionKey + // NSNextFunctionKey + // NSSelectFunctionKey + // NSExecuteFunctionKey + // NSUndoFunctionKey + // NSRedoFunctionKey + // NSFindFunctionKey + // NSHelpFunctionKey + // NSModeSwitchFunctionKey + default: break; + } + } + + if ('a' <= keyChar && keyChar <= 'z') { + return KeyEvent.VK_A + ( keyChar - 'a' ) ; + } + + return (int) keyChar; // let's hope for the best (compatibility of keyChar/keyCode's) + } +} diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java index d09ac72ba..b7e572b6c 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java @@ -37,105 +37,19 @@ package jogamp.newt.driver.macosx; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.SurfaceChangeable; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.PointImmutable; import jogamp.newt.WindowImpl; +import jogamp.newt.driver.DriverClearFocus; import com.jogamp.newt.event.KeyEvent; -public class MacWindow extends WindowImpl { +public class MacWindow extends WindowImpl implements SurfaceChangeable, DriverClearFocus { - // Window styles - private static final int NSBorderlessWindowMask = 0; - private static final int NSTitledWindowMask = 1 << 0; - private static final int NSClosableWindowMask = 1 << 1; - private static final int NSMiniaturizableWindowMask = 1 << 2; - private static final int NSResizableWindowMask = 1 << 3; - - // Window backing store types - private static final int NSBackingStoreRetained = 0; - private static final int NSBackingStoreNonretained = 1; - private static final int NSBackingStoreBuffered = 2; - - // Key constants handled differently on Mac OS X than other platforms - private static final int NSUpArrowFunctionKey = 0xF700; - private static final int NSDownArrowFunctionKey = 0xF701; - private static final int NSLeftArrowFunctionKey = 0xF702; - private static final int NSRightArrowFunctionKey = 0xF703; - private static final int NSF1FunctionKey = 0xF704; - private static final int NSF2FunctionKey = 0xF705; - private static final int NSF3FunctionKey = 0xF706; - private static final int NSF4FunctionKey = 0xF707; - private static final int NSF5FunctionKey = 0xF708; - private static final int NSF6FunctionKey = 0xF709; - private static final int NSF7FunctionKey = 0xF70A; - private static final int NSF8FunctionKey = 0xF70B; - private static final int NSF9FunctionKey = 0xF70C; - private static final int NSF10FunctionKey = 0xF70D; - private static final int NSF11FunctionKey = 0xF70E; - private static final int NSF12FunctionKey = 0xF70F; - private static final int NSF13FunctionKey = 0xF710; - private static final int NSF14FunctionKey = 0xF711; - private static final int NSF15FunctionKey = 0xF712; - private static final int NSF16FunctionKey = 0xF713; - private static final int NSF17FunctionKey = 0xF714; - private static final int NSF18FunctionKey = 0xF715; - private static final int NSF19FunctionKey = 0xF716; - private static final int NSF20FunctionKey = 0xF717; - private static final int NSF21FunctionKey = 0xF718; - private static final int NSF22FunctionKey = 0xF719; - private static final int NSF23FunctionKey = 0xF71A; - private static final int NSF24FunctionKey = 0xF71B; - private static final int NSF25FunctionKey = 0xF71C; - private static final int NSF26FunctionKey = 0xF71D; - private static final int NSF27FunctionKey = 0xF71E; - private static final int NSF28FunctionKey = 0xF71F; - private static final int NSF29FunctionKey = 0xF720; - private static final int NSF30FunctionKey = 0xF721; - private static final int NSF31FunctionKey = 0xF722; - private static final int NSF32FunctionKey = 0xF723; - private static final int NSF33FunctionKey = 0xF724; - private static final int NSF34FunctionKey = 0xF725; - private static final int NSF35FunctionKey = 0xF726; - private static final int NSInsertFunctionKey = 0xF727; - private static final int NSDeleteFunctionKey = 0xF728; - private static final int NSHomeFunctionKey = 0xF729; - private static final int NSBeginFunctionKey = 0xF72A; - private static final int NSEndFunctionKey = 0xF72B; - private static final int NSPageUpFunctionKey = 0xF72C; - private static final int NSPageDownFunctionKey = 0xF72D; - private static final int NSPrintScreenFunctionKey = 0xF72E; - private static final int NSScrollLockFunctionKey = 0xF72F; - private static final int NSPauseFunctionKey = 0xF730; - private static final int NSSysReqFunctionKey = 0xF731; - private static final int NSBreakFunctionKey = 0xF732; - private static final int NSResetFunctionKey = 0xF733; - private static final int NSStopFunctionKey = 0xF734; - private static final int NSMenuFunctionKey = 0xF735; - private static final int NSUserFunctionKey = 0xF736; - private static final int NSSystemFunctionKey = 0xF737; - private static final int NSPrintFunctionKey = 0xF738; - private static final int NSClearLineFunctionKey = 0xF739; - private static final int NSClearDisplayFunctionKey = 0xF73A; - private static final int NSInsertLineFunctionKey = 0xF73B; - private static final int NSDeleteLineFunctionKey = 0xF73C; - private static final int NSInsertCharFunctionKey = 0xF73D; - private static final int NSDeleteCharFunctionKey = 0xF73E; - private static final int NSPrevFunctionKey = 0xF73F; - private static final int NSNextFunctionKey = 0xF740; - private static final int NSSelectFunctionKey = 0xF741; - private static final int NSExecuteFunctionKey = 0xF742; - private static final int NSUndoFunctionKey = 0xF743; - private static final int NSRedoFunctionKey = 0xF744; - private static final int NSFindFunctionKey = 0xF745; - private static final int NSHelpFunctionKey = 0xF746; - private static final int NSModeSwitchFunctionKey = 0xF747; - - private volatile long surfaceHandle; - static { MacDisplay.initSingleton(); } @@ -143,6 +57,7 @@ public class MacWindow extends WindowImpl { public MacWindow() { } + @Override protected void createNativeImpl() { config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); @@ -155,6 +70,7 @@ public class MacWindow extends WindowImpl { } } + @Override protected void closeNativeImpl() { try { if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } @@ -173,76 +89,128 @@ public class MacWindow extends WindowImpl { @Override protected int lockSurfaceImpl() { - return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + if(!isOffscreenInstance) { + return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + } + return LOCK_SUCCESS; } @Override protected void unlockSurfaceImpl() { - unlockSurface0(getWindowHandle()); + if(!isOffscreenInstance) { + unlockSurface0(getWindowHandle()); + } } @Override public final long getSurfaceHandle() { - return surfaceHandle; + return 0 != sscSurfaceHandle ? sscSurfaceHandle : surfaceHandle; + } + + public void setSurfaceHandle(long surfaceHandle) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + } + sscSurfaceHandle = surfaceHandle; + if (isNativeValid()) { + if (0 != sscSurfaceHandle) { + orderOut0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() ); + } /** this is done by recreation! + else if (isVisible()){ + orderFront0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() ); + } */ + } } + public void surfaceSizeChanged(int width, int height) { + sizeChanged(false, width, height, false); + } + @Override protected void setTitleImpl(final String title) { setTitle0(getWindowHandle(), title); } protected void requestFocusImpl(boolean force) { - requestFocus0(getWindowHandle(), force); + if(!isOffscreenInstance) { + requestFocus0(getWindowHandle(), force); + } else { + focusChanged(false, true); + } + } + + public final void clearFocus() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: clearFocus() - requestFocusParent, isOffscreenInstance "+isOffscreenInstance); + } + if(!isOffscreenInstance) { + requestFocusParent0(getWindowHandle()); + } else { + focusChanged(false, false); + } } protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { final PointImmutable pS = position2TopLevel(new Point(x, y)); + isOffscreenInstance = 0 != sscSurfaceHandle || isOffscreenInstance(this, this.getParent()); if(DEBUG_IMPLEMENTATION) { - System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+", "+ - getReconfigureFlagsAsString(null, flags)); + System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+ + ", offscreenInstance "+isOffscreenInstance+ + ", "+getReconfigureFlagsAsString(null, flags)); } if( getWindowHandle() == 0 ) { if( 0 != ( FLAG_IS_VISIBLE & flags) ) { - createWindow(false, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); + createWindow(isOffscreenInstance, false, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); // no native event .. visibleChanged(true, true); } /* else { ?? } */ } else { if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 == ( FLAG_IS_VISIBLE & flags) ) { - orderOut0(getWindowHandle()); + if ( !isOffscreenInstance ) { + orderOut0(getWindowHandle()); + } // no native event .. visibleChanged(true, false); - } + } if( 0 != ( FLAG_CHANGE_DECORATION & flags) || 0 != ( FLAG_CHANGE_PARENTING & flags) || 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { - createWindow(true, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); + createWindow(isOffscreenInstance, true, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); if(isVisible()) { flags |= FLAG_CHANGE_VISIBILITY; } } if(x>=0 && y>=0) { - setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); + if( !isOffscreenInstance ) { + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); + } // else no offscreen position // no native event (fullscreen, some reparenting) positionChanged(true, getLocationOnScreenImpl(0, 0)); // incl. validation } if(width>0 && height>0) { - setContentSize0(getWindowHandle(), width, height); + if( !isOffscreenInstance ) { + setContentSize0(getWindowHandle(), width, height); + } // else offscreen size is realized via recreation // no native event (fullscreen, some reparenting) sizeChanged(true, width, height, false); // incl. validation (incl. repositioning) } if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 != ( FLAG_IS_VISIBLE & flags) ) { - orderFront0(getWindowHandle()); + if( !isOffscreenInstance ) { + orderFront0(getWindowHandle()); + } // no native event .. visibleChanged(true, true); } - setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags)); + if( !isOffscreenInstance ) { + setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags)); + } } return true; } protected Point getLocationOnScreenImpl(int x, int y) { - return (Point) getLocationOnScreen0(getWindowHandle(), x, y); + return position2TopLevel(new Point(x, y)); // allows offscreen .. + // return (Point) getLocationOnScreen0(getWindowHandle(), x, y); } protected void updateInsetsImpl(Insets insets) { @@ -265,125 +233,54 @@ public class MacWindow extends WindowImpl { @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { - return setPointerVisible0(getWindowHandle(), pointerVisible); + if( !isOffscreenInstance ) { + return setPointerVisible0(getWindowHandle(), pointerVisible); + } // else may need offscreen solution ? FIXME + return false; } @Override protected boolean confinePointerImpl(final boolean confine) { - return confinePointer0(getWindowHandle(), confine); + if( !isOffscreenInstance ) { + return confinePointer0(getWindowHandle(), confine); + } // else may need offscreen solution ? FIXME + return false; } @Override protected void warpPointerImpl(final int x, final int y) { - warpPointer0(getWindowHandle(), x, y); + if( !isOffscreenInstance ) { + warpPointer0(getWindowHandle(), x, y); + } // else may need offscreen solution ? FIXME } @Override public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { - final int key = convertKeyChar(keyChar); - if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()); // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system - super.sendKeyEvent(eventType, modifiers, key, keyChar); + final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar); + if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)); + // only deliver keyChar on key Typed events, harmonizing platform behavior + keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1; + super.sendKeyEvent(eventType, modifiers, keyCode2, keyChar); } @Override public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { - final int key = convertKeyChar(keyChar); - if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()); // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system - super.enqueueKeyEvent(wait, eventType, modifiers, key, keyChar); + final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar); + if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)); + // only deliver keyChar on key Typed events, harmonizing platform behavior + keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1; + super.enqueueKeyEvent(wait, eventType, modifiers, keyCode2, keyChar); } //---------------------------------------------------------------------- // Internals only // - private char convertKeyChar(char keyChar) { - if (keyChar == '\r') { - // Turn these into \n - return '\n'; - } - - if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { - switch (keyChar) { - case NSUpArrowFunctionKey: return KeyEvent.VK_UP; - case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; - case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; - case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; - case NSF1FunctionKey: return KeyEvent.VK_F1; - case NSF2FunctionKey: return KeyEvent.VK_F2; - case NSF3FunctionKey: return KeyEvent.VK_F3; - case NSF4FunctionKey: return KeyEvent.VK_F4; - case NSF5FunctionKey: return KeyEvent.VK_F5; - case NSF6FunctionKey: return KeyEvent.VK_F6; - case NSF7FunctionKey: return KeyEvent.VK_F7; - case NSF8FunctionKey: return KeyEvent.VK_F8; - case NSF9FunctionKey: return KeyEvent.VK_F9; - case NSF10FunctionKey: return KeyEvent.VK_F10; - case NSF11FunctionKey: return KeyEvent.VK_F11; - case NSF12FunctionKey: return KeyEvent.VK_F12; - case NSF13FunctionKey: return KeyEvent.VK_F13; - case NSF14FunctionKey: return KeyEvent.VK_F14; - case NSF15FunctionKey: return KeyEvent.VK_F15; - case NSF16FunctionKey: return KeyEvent.VK_F16; - case NSF17FunctionKey: return KeyEvent.VK_F17; - case NSF18FunctionKey: return KeyEvent.VK_F18; - case NSF19FunctionKey: return KeyEvent.VK_F19; - case NSF20FunctionKey: return KeyEvent.VK_F20; - case NSF21FunctionKey: return KeyEvent.VK_F21; - case NSF22FunctionKey: return KeyEvent.VK_F22; - case NSF23FunctionKey: return KeyEvent.VK_F23; - case NSF24FunctionKey: return KeyEvent.VK_F24; - case NSInsertFunctionKey: return KeyEvent.VK_INSERT; - case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; - case NSHomeFunctionKey: return KeyEvent.VK_HOME; - case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; - case NSEndFunctionKey: return KeyEvent.VK_END; - case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; - case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; - case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; - case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; - case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; - // Not handled: - // NSSysReqFunctionKey - // NSBreakFunctionKey - // NSResetFunctionKey - case NSStopFunctionKey: return KeyEvent.VK_STOP; - // Not handled: - // NSMenuFunctionKey - // NSUserFunctionKey - // NSSystemFunctionKey - // NSPrintFunctionKey - // NSClearLineFunctionKey - // NSClearDisplayFunctionKey - // NSInsertLineFunctionKey - // NSDeleteLineFunctionKey - // NSInsertCharFunctionKey - // NSDeleteCharFunctionKey - // NSPrevFunctionKey - // NSNextFunctionKey - // NSSelectFunctionKey - // NSExecuteFunctionKey - // NSUndoFunctionKey - // NSRedoFunctionKey - // NSFindFunctionKey - // NSHelpFunctionKey - // NSModeSwitchFunctionKey - default: break; - } - } - - // NSEvent's charactersIgnoringModifiers doesn't ignore the shift key - if (keyChar >= 'a' && keyChar <= 'z') { - return Character.toUpperCase(keyChar); - } - - return keyChar; - } - - private void createWindow(final boolean recreate, + private void createWindow(final boolean offscreenInstance, final boolean recreate, final PointImmutable pS, final int width, final int height, final boolean fullscreen) { @@ -406,20 +303,24 @@ public class MacWindow extends WindowImpl { } setWindowHandle(createWindow0(getParentWindowHandle(), pS.getX(), pS.getY(), width, height, - config.getChosenCapabilities().isBackgroundOpaque(), + (config.getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance), fullscreen, - (isUndecorated() ? - NSBorderlessWindowMask : - NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), + ((isUndecorated() || offscreenInstance) ? + NSBorderlessWindowMask : + NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), NSBackingStoreBuffered, getScreen().getIndex(), surfaceHandle)); if (getWindowHandle() == 0) { throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); } surfaceHandle = contentView0(getWindowHandle()); - setTitle0(getWindowHandle(), getTitle()); - // need to revalidate real position - positionChanged(true, getLocationOnScreenImpl(0, 0)); // incl. validation + if( offscreenInstance ) { + orderOut0(0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle()); + } else { + setTitle0(getWindowHandle(), getTitle()); + // need to revalidate real position + positionChanged(true, getLocationOnScreenImpl(0, 0)); // incl. validation + } } catch (Exception ie) { ie.printStackTrace(); } @@ -467,6 +368,7 @@ public class MacWindow extends WindowImpl { private native boolean lockSurface0(long window); private native void unlockSurface0(long window); private native void requestFocus0(long window, boolean force); + private native void requestFocusParent0(long window); /** in case of a child window, it actually only issues orderBack(..) */ private native void orderOut0(long window); private native void orderFront0(long window); @@ -481,4 +383,21 @@ public class MacWindow extends WindowImpl { private static native boolean setPointerVisible0(long windowHandle, boolean visible); private static native boolean confinePointer0(long windowHandle, boolean confine); private static native void warpPointer0(long windowHandle, int x, int y); + + // Window styles + private static final int NSBorderlessWindowMask = 0; + private static final int NSTitledWindowMask = 1 << 0; + private static final int NSClosableWindowMask = 1 << 1; + private static final int NSMiniaturizableWindowMask = 1 << 2; + private static final int NSResizableWindowMask = 1 << 3; + + // Window backing store types + private static final int NSBackingStoreRetained = 0; + private static final int NSBackingStoreNonretained = 1; + private static final int NSBackingStoreBuffered = 2; + + private volatile long surfaceHandle; + private long sscSurfaceHandle; + private boolean isOffscreenInstance; + } diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java index cd5909d42..28be93acd 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java @@ -42,6 +42,7 @@ import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; +import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; @@ -244,6 +245,36 @@ public class WindowsWindow extends WindowImpl { // nop - using event driven insetsChange(..) } + private final int validateKeyCode(int eventType, int keyCode) { + switch(eventType) { + case KeyEvent.EVENT_KEY_PRESSED: + lastPressedKeyCode = keyCode; + break; + case KeyEvent.EVENT_KEY_TYPED: + if(-1==keyCode) { + keyCode = lastPressedKeyCode; + } + lastPressedKeyCode = -1; + break; + } + return keyCode; + } + private int lastPressedKeyCode = 0; + + @Override + public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { + // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform + keyCode = validateKeyCode(eventType, keyCode); + super.sendKeyEvent(eventType, modifiers, keyCode, keyChar); + } + + @Override + public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { + // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform + keyCode = validateKeyCode(eventType, keyCode); + super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar); + } + //---------------------------------------------------------------------- // Internals only // diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index a13ffaf31..3a5a7cff6 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -48,7 +48,6 @@ static const char * const ClazzAnyCstrName = "<init>"; static const char * const ClazzNamePointCstrSignature = "(II)V"; static jclass pointClz = NULL; static jmethodID pointCstr = NULL; -static jmethodID focusActionID = NULL; static NSString* jstringToNSString(JNIEnv* env, jstring jstr) { @@ -272,11 +271,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacWindow_initIDs0 ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); - if(NULL==focusActionID) { - NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch method focusAction()Z"); - } - // Need this when debugging, as it is necessary to attach gdb to // the running java process -- "gdb java" doesn't work // printf("Going to sleep for 10 seconds\n"); @@ -510,26 +504,44 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_requestFocus0 (JNIEnv *env, jobject window, jlong w, jboolean force) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) w); + NSWindow* mWin = (NSWindow*) ((intptr_t) w); #ifdef VERBOSE_ON - BOOL hasFocus = [win isKeyWindow]; + BOOL hasFocus = [mWin isKeyWindow]; #endif - DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", win, force, hasFocus); - - // Even if we already own the focus, we need the 'focusAction()' call - // and the other probably redundant NS calls to force proper focus traversal - // of the parent TK (AWT doesn't do it properly on OSX). - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - DBG_PRINT( "makeKeyWindow win %p\n", win); - // [win performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:YES]; - // [win performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:YES]; - [win orderFrontRegardless]; - [win makeKeyWindow]; - [win makeFirstResponder: nil]; - } + DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus); + + [mWin makeFirstResponder: nil]; + // [mWin performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:YES]; + // [mWin performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:YES]; + [mWin orderFrontRegardless]; + [mWin makeKeyWindow]; + + DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", mWin, force); - DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", win, force); + [pool release]; +} + +/* + * Class: jogamp_newt_driver_macosx_MacWindow + * Method: requestFocusParent0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_requestFocusParent0 + (JNIEnv *env, jobject window, jlong w) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* mWin = (NSWindow*) ((intptr_t) w); + NSWindow* pWin = [mWin parentWindow]; +#ifdef VERBOSE_ON + BOOL hasFocus = [mWin isKeyWindow]; +#endif + + DBG_PRINT( "requestFocusParent0 - window: %p, parent: %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); + if(NULL != pWin) { + [pWin makeKeyWindow]; + } + DBG_PRINT( "requestFocusParent0 - window: %p, parent: %p (END)\n", mWin, pWin); [pool release]; } diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index cb256e71f..861811b6c 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -37,10 +37,11 @@ #include "NewtCommon.h" -// #define VERBOSE_ON 1 +#define VERBOSE_ON 1 #ifdef VERBOSE_ON - #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) #else #define DBG_PRINT(...) #endif diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 1f74742ec..a3b6fa871 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -76,7 +76,7 @@ static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; @@ -252,7 +252,7 @@ static jmethodID windowRepaintID = NULL; int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if(NULL==env) { - NSLog(@"viewDidHide: null JNIEnv"); + DBG_PRINT("viewDidHide: null JNIEnv\n"); return; } @@ -272,7 +272,7 @@ static jmethodID windowRepaintID = NULL; int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if(NULL==env) { - NSLog(@"viewDidHide: null JNIEnv"); + DBG_PRINT("viewDidHide: null JNIEnv\n"); return; } @@ -290,7 +290,7 @@ static jmethodID windowRepaintID = NULL; int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if(NULL==env) { - NSLog(@"viewDidHide: null JNIEnv"); + DBG_PRINT("viewDidHide: null JNIEnv\n"); return; } @@ -325,9 +325,9 @@ static jmethodID windowRepaintID = NULL; focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (enqueueMouseEventID && sendMouseEventID && enqueueKeyEventID && sendKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID && - positionChangedID && focusChangedID && windowDestroyNotifyID && enqueueRequestFocusID && windowRepaintID) + positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) { return YES; } @@ -512,14 +512,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"sendKeyEvent: null javaWindowObject"); + DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"sendKeyEvent: null JNIEnv"); + DBG_PRINT("sendKeyEvent: null JNIEnv\n"); return; } @@ -533,6 +533,8 @@ static jint mods2JavaMods(NSUInteger mods) // Note: the key code in the NSEvent does not map to anything we can use jchar keyChar = (jchar) [chars characterAtIndex: i]; + DBG_PRINT("sendKeyEvent: %d/%d char 0x%X, code 0x%X\n", i, len, (int)keyChar, (int)keyCode); + #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID, evType, javaMods, keyCode, keyChar); @@ -567,14 +569,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"sendMouseEvent: null javaWindowObject"); + DBG_PRINT("sendMouseEvent: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"sendMouseEvent: null JNIEnv"); + DBG_PRINT("sendMouseEvent: null JNIEnv\n"); return; } jint javaMods = mods2JavaMods([event modifierFlags]); @@ -613,7 +615,7 @@ static jint mods2JavaMods(NSUInteger mods) return; } if (evType == EVENT_MOUSE_PRESSED) { - (*env)->CallVoidMethod(env, javaWindowObject, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, javaWindowObject, requestFocusID, JNI_FALSE); } NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]]; @@ -770,14 +772,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"windowDidResize: null javaWindowObject"); + DBG_PRINT("windowDidResize: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"windowDidResize: null JNIEnv"); + DBG_PRINT("windowDidResize: null JNIEnv\n"); return; } @@ -805,14 +807,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"windowDidMove: null javaWindowObject"); + DBG_PRINT("windowDidMove: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"windowDidMove: null JNIEnv"); + DBG_PRINT("windowDidMove: null JNIEnv\n"); return; } @@ -841,14 +843,14 @@ static jint mods2JavaMods(NSUInteger mods) jobject javaWindowObject = [view getJavaWindowObject]; DBG_PRINT( "*************** windowWillClose.0: 0x%p\n", (void *)(intptr_t)javaWindowObject); if (javaWindowObject == NULL) { - NSLog(@"windowWillClose: null javaWindowObject"); + DBG_PRINT("windowWillClose: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"windowWillClose: null JNIEnv"); + DBG_PRINT("windowWillClose: null JNIEnv\n"); return; } @@ -916,14 +918,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"focusChanged: null javaWindowObject"); + DBG_PRINT("focusChanged: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"focusChanged: null JNIEnv"); + DBG_PRINT("focusChanged: null JNIEnv\n"); return; } diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index d60c40496..b654fbe85 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -115,8 +115,7 @@ static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID focusActionID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd); @@ -602,18 +601,14 @@ static void NewtWindows_requestFocus (JNIEnv *env, jobject window, HWND hwnd, jb (void*) pHwnd, (void*)hwnd, current==hwnd); if( JNI_TRUE==force || current!=hwnd) { - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); - SetForegroundWindow(hwnd); // Slightly Higher Priority - SetFocus(hwnd);// Sets Keyboard Focus To Window - if(NULL!=pHwnd) { - SetActiveWindow(hwnd); - } - DBG_PRINT("*** WindowsWindow: requestFocus.X1\n"); - } else { - DBG_PRINT("*** WindowsWindow: requestFocus.X0\n"); + UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); + SetForegroundWindow(hwnd); // Slightly Higher Priority + SetFocus(hwnd);// Sets Keyboard Focus To Window + if(NULL!=pHwnd) { + SetActiveWindow(hwnd); } + DBG_PRINT("*** WindowsWindow: requestFocus.X1\n"); } DBG_PRINT("*** WindowsWindow: requestFocus.XX\n"); } @@ -870,7 +865,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_LBUTTONDOWN: DBG_PRINT("*** WindowsWindow: LBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -890,7 +885,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_MBUTTONDOWN: DBG_PRINT("*** WindowsWindow: MBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -910,7 +905,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_RBUTTONDOWN: DBG_PRINT("*** WindowsWindow: RBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -1270,8 +1265,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (insetsChangedID == NULL || sizeChangedID == NULL || @@ -1284,8 +1278,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs sendMouseEventID == NULL || enqueueKeyEventID == NULL || sendKeyEventID == NULL || - focusActionID == NULL || - enqueueRequestFocusID == NULL) { + requestFocusID == NULL) { return JNI_FALSE; } BuildDynamicKeyMapTable(); diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index f14138a0a..3613f0018 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -105,34 +105,91 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { if(IS_WITHIN(keySym,XK_F1,XK_F12)) return (keySym-XK_F1)+J_VK_F1; + if(IS_WITHIN(keySym,XK_KP_0,XK_KP_9)) + return (keySym-XK_KP_0)+J_VK_NUMPAD0; switch(keySym) { + case XK_Return: + case XK_KP_Enter: + return J_VK_ENTER; + case XK_BackSpace: + return J_VK_BACK_SPACE; + case XK_Tab: + case XK_KP_Tab: + case XK_ISO_Left_Tab: + return J_VK_TAB; + case XK_Cancel: + return J_VK_CANCEL; + case XK_Clear: + return J_VK_CLEAR; + case XK_Shift_L: + case XK_Shift_R: + return J_VK_SHIFT; + case XK_Control_L: + case XK_Control_R: + return J_VK_CONTROL; case XK_Alt_L: case XK_Alt_R: return J_VK_ALT; - + case XK_Pause: + return J_VK_PAUSE; + case XK_Caps_Lock: + return J_VK_CAPS_LOCK; + case XK_Escape: + return J_VK_ESCAPE; + case XK_space: + case XK_KP_Space: + return J_VK_SPACE; + case XK_Page_Up: + case XK_KP_Page_Up: + return J_VK_PAGE_UP; + case XK_Page_Down: + case XK_KP_Page_Down: + return J_VK_PAGE_DOWN; + case XK_End: + case XK_KP_End: + return J_VK_END; + case XK_Home: + case XK_KP_Home: + return J_VK_HOME; case XK_Left: + case XK_KP_Left: return J_VK_LEFT; - case XK_Right: - return J_VK_RIGHT; case XK_Up: + case XK_KP_Up: return J_VK_UP; + case XK_Right: + case XK_KP_Right: + return J_VK_RIGHT; case XK_Down: + case XK_KP_Down: return J_VK_DOWN; - case XK_Page_Up: - return J_VK_PAGE_UP; - case XK_Page_Down: - return J_VK_PAGE_DOWN; - case XK_Shift_L: - case XK_Shift_R: - return J_VK_SHIFT; - case XK_Control_L: - case XK_Control_R: - return J_VK_CONTROL; - case XK_Escape: - return J_VK_ESCAPE; + case XK_KP_Multiply: + return J_VK_MULTIPLY; + case XK_KP_Add: + return J_VK_ADD; + case XK_KP_Separator: + return J_VK_SEPARATOR; + case XK_KP_Subtract: + return J_VK_SUBTRACT; + case XK_KP_Decimal: + return J_VK_DECIMAL; + case XK_KP_Divide: + return J_VK_DIVIDE; case XK_Delete: + case XK_KP_Delete: return J_VK_DELETE; + case XK_Num_Lock: + return J_VK_NUM_LOCK; + case XK_Scroll_Lock: + return J_VK_SCROLL_LOCK; + case XK_Print: + return J_VK_PRINTSCREEN; + case XK_Insert: + case XK_KP_Insert: + return J_VK_INSERT; + case XK_Help: + return J_VK_HELP; } return keySym; } @@ -179,8 +236,7 @@ static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID focusActionID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static jmethodID displayCompletedID = NULL; @@ -535,16 +591,14 @@ static void NewtWindows_requestFocus (JNIEnv *env, jobject window, Display *dpy, DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d, hasFocus %d\n", dpy, (void*)w, force, focus_return==w); if( JNI_TRUE==force || focus_return!=w) { - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - DBG_PRINT( "X11: XRaiseWindow dpy %p, win %p\n", dpy, (void*)w); - XRaiseWindow(dpy, w); - NewtWindows_setCWAbove(dpy, w); - // Avoid 'BadMatch' errors from XSetInputFocus, ie if window is not viewable - XGetWindowAttributes(dpy, w, &xwa); - if(xwa.map_state == IsViewable) { - DBG_PRINT( "X11: XSetInputFocus dpy %p,win %pd\n", dpy, (void*)w); - XSetInputFocus(dpy, w, RevertToParent, CurrentTime); - } + DBG_PRINT( "X11: XRaiseWindow dpy %p, win %p\n", dpy, (void*)w); + XRaiseWindow(dpy, w); + NewtWindows_setCWAbove(dpy, w); + // Avoid 'BadMatch' errors from XSetInputFocus, ie if window is not viewable + XGetWindowAttributes(dpy, w, &xwa); + if(xwa.map_state == IsViewable) { + DBG_PRINT( "X11: XSetInputFocus dpy %p,win %pd\n", dpy, (void*)w); + XSetInputFocus(dpy, w, RevertToParent, CurrentTime); } } DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d - FIN\n", dpy, (void*)w, force); @@ -787,11 +841,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 keyChar=text[0]; XConvertCase(keySym, &lower_return, &upper_return); // always return upper case, set modifier masks (SHIFT, ..) - keySym = upper_return; - modifiers = X11InputState2NewtModifiers(evt.xkey.state); + keySym = X11KeySym2NewtVKey(upper_return); } else { keyChar=0; + keySym = X11KeySym2NewtVKey(keySym); } + modifiers = X11InputState2NewtModifiers(evt.xkey.state); break; case ButtonPress: @@ -806,7 +861,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 switch(evt.type) { case ButtonPress: - (*env)->CallVoidMethod(env, jwindow, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, modifiers, @@ -866,26 +921,26 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 case KeyPress: #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); #else (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); #endif break; case KeyRelease: #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_TYPED, - modifiers, (jint) -1, (jchar) keyChar); + modifiers, keySym, (jchar) keyChar); #else (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_TYPED, - modifiers, (jint) -1, (jchar) keyChar); + modifiers, keySym, (jchar) keyChar); #endif break; @@ -1480,8 +1535,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Window_initIDs0 sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (insetsChangedID == NULL || sizeChangedID == NULL || @@ -1495,8 +1549,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Window_initIDs0 sendMouseEventID == NULL || enqueueKeyEventID == NULL || sendKeyEventID == NULL || - focusActionID == NULL || - enqueueRequestFocusID == NULL) { + requestFocusID == NULL) { return JNI_FALSE; } return JNI_TRUE; diff --git a/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java index 21eb8af2d..74419e564 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java @@ -62,7 +62,7 @@ public class NEWTElektronActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new ElektronenMultiplizierer()); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java index 337dafc71..ba861d012 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java @@ -62,7 +62,7 @@ public class NEWTGearsES1Activity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GearsES1(1)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java index 6abb0b354..89ecf4cb9 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java @@ -65,7 +65,7 @@ public class NEWTGearsES2Activity extends NewtBaseActivity { GearsES2 demo = new GearsES2(0); // demo.enableAndroidTrace(true); glWindow.addGLEventListener(demo); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java index 691151ef3..d6b7507a3 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java @@ -61,7 +61,7 @@ public class NEWTGearsES2TransActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GearsES2(1)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java index 83f35879b..1efedcd6d 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java @@ -61,7 +61,7 @@ public class NEWTGraphUI1pActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GPUUISceneGLListener0A(0)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java index 17924d43d..39fb5e2cc 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java @@ -62,7 +62,7 @@ public class NEWTGraphUI2pActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GPUUISceneGLListener0A(Region.VBAA_RENDERING_BIT)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java index 24b4eaf0c..99d7fd723 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java @@ -61,7 +61,7 @@ public class NEWTRedSquareES1Activity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new RedSquareES1(1)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java index 51cddd523..804e627a5 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java @@ -64,7 +64,7 @@ public class NEWTRedSquareES2Activity extends NewtBaseActivity { final RedSquareES2 demo = new RedSquareES2(0); // demo.enableAndroidTrace(true); glWindow.addGLEventListener(demo); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java index 8d579ce5d..b5a729e02 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java @@ -21,6 +21,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es1; +import javax.media.nativewindow.NativeWindow; import javax.media.opengl.GL; import javax.media.opengl.GL2ES1; import javax.media.opengl.GLAutoDrawable; @@ -181,8 +182,18 @@ public class GearsES1 implements GLEventListener { // Get the GL corresponding to the drawable we are animating GL2ES1 gl = drawable.getGL().getGL2ES1(); - gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - + final boolean hasFocus; + if(drawable.getNativeSurface() instanceof NativeWindow) { + hasFocus = ((NativeWindow)drawable.getNativeSurface()).hasFocus(); + } else { + hasFocus = true; + } + if(hasFocus) { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } else { + gl.glClearColor(0.2f, 0.2f, 0.2f, 0.0f); + } + // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if (GLProfile.isAWTAvailable() && diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index 3fa61bf1d..51bc7d137 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -34,6 +34,8 @@ import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; import com.jogamp.opengl.util.glsl.ShaderState; import java.nio.FloatBuffer; + +import javax.media.nativewindow.NativeWindow; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; @@ -244,8 +246,18 @@ public class GearsES2 implements GLEventListener { // Get the GL corresponding to the drawable we are animating GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - + final boolean hasFocus; + if(drawable.getNativeSurface() instanceof NativeWindow) { + hasFocus = ((NativeWindow)drawable.getNativeSurface()).hasFocus(); + } else { + hasFocus = true; + } + if(hasFocus) { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } else { + gl.glClearColor(0.2f, 0.2f, 0.2f, 0.0f); + } + // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if (GLProfile.isAWTAvailable() && diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java index 01790de10..d645fb9f8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java @@ -205,7 +205,7 @@ public class RedSquareES2 implements GLEventListener { class MyMouseAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { System.err.println(e); - if(null != glWindow && e.getSource() == glWindow.getWindow()) { + if(null != glWindow && e.getSource() == glWindow.getDelegatedWindow()) { if(e.getX() < glWindow.getWidth()/2) { glWindow.setFullscreen(!glWindow.isFullscreen()); System.err.println("setFullscreen: "+glWindow.isFullscreen()); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java index 8ab641267..83e3663dc 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java @@ -72,7 +72,7 @@ public class TestGearsAWT extends UITestCase { frame.add(glCanvas); frame.setSize(512, 512); - glCanvas.addGLEventListener(new Gears()); + glCanvas.addGLEventListener(new Gears(1)); Animator animator = new Animator(glCanvas); QuitAdapter quitAdapter = new QuitAdapter(); @@ -81,7 +81,7 @@ public class TestGearsAWT extends UITestCase { new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter)).addTo(frame); frame.setVisible(true); - animator.setUpdateFPSFrames(1, null); + animator.setUpdateFPSFrames(60, System.err); animator.start(); while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java index 199b094f2..1d1ee1e0c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java @@ -103,7 +103,7 @@ public class WindowUtilNEWT { while ( windowOffScreen.getTotalFPSFrames() < frames) { windowOffScreen.display(); } - windowOffScreen.removeAllSurfaceUpdatedListener(); + windowOffScreen.removeSurfaceUpdatedListener(ul); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java index 3e153214b..b2a7e9a5e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java @@ -156,7 +156,7 @@ public class TestSWT02GLn extends UITestCase { ProxySurface proxySurface = factory.createProxySurface(device, nativeWindowHandle, caps, null); Assert.assertNotNull( proxySurface ); - proxySurface.setSize( 640, 480 ); + proxySurface.surfaceSizeChanged( 640, 480 ); System.err.println("*** ProxySurface: " + proxySurface); final GLDrawable drawable = factory.createGLDrawable(proxySurface); Assert.assertNotNull( drawable ); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java index adc885191..664cab03b 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java @@ -39,10 +39,9 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.util.Point; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLProfile; + import com.jogamp.newt.Window; import com.jogamp.newt.awt.NewtCanvasAWT; -import com.jogamp.newt.event.WindowAdapter; -import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -53,6 +52,7 @@ public class TestCloseNewtAWT extends UITestCase { NewtCanvasAWT newtCanvas = null; JFrame frame = null; + @SuppressWarnings("serial") class MyCanvas extends NewtCanvasAWT { public MyCanvas(Window window) { super(window); @@ -78,7 +78,7 @@ public class TestCloseNewtAWT extends UITestCase { NativeWindow nw = MyCanvas.this.getNativeWindow(); if(null != nw) { Point p = nw.getLocationOnScreen(null); - System.err.println("MyCanvas On NEWT-EDT: position: "+p); + System.err.println("MyCanvas On NEWT-EDT: position: "+p); } else { System.err.println("MyCanvas On NEWT-EDT: position n/a, null NativeWindow"); } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java index 13653b907..fe7fef09f 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java @@ -35,6 +35,7 @@ import org.junit.Assume; import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Button; +import java.awt.Color; import java.awt.Robot; import java.lang.reflect.InvocationTargetException; @@ -119,7 +120,7 @@ public class TestFocus01SwingAWTRobot extends UITestCase { AWTFocusAdapter frame1FA = new AWTFocusAdapter("frame1"); frame1.addFocusListener(frame1FA); frame1.getContentPane().add(newtCanvasAWT, BorderLayout.CENTER); - Button button = new Button("Click me .."); + final Button button = new Button("Click me .."); AWTFocusAdapter buttonFA = new AWTFocusAdapter("Button"); button.addFocusListener(buttonFA); AWTKeyAdapter buttonKA = new AWTKeyAdapter("Button"); @@ -127,7 +128,10 @@ public class TestFocus01SwingAWTRobot extends UITestCase { eventCountAdapters.add(buttonKA); frame1.getContentPane().add(button, BorderLayout.NORTH); frame1.setSize(width, height); - frame1.setVisible(true); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.setVisible(true); + } } ); Assert.assertTrue(AWTRobotUtil.toFront(robot, frame1)); Thread.sleep(durationPerTest); // manual testing @@ -162,7 +166,6 @@ public class TestFocus01SwingAWTRobot extends UITestCase { System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); AWTRobotUtil.assertRequestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonFA); - Assert.assertTrue(AWTRobotUtil.waitForFocusCount(false, newtCanvasAWTFA)); Assert.assertEquals(true, glWindow1FA.focusGained()); Assert.assertEquals(false, buttonFA.focusGained()); Assert.assertEquals(true, buttonFA.focusLost()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java index 56b08b52a..b9eb748b7 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java @@ -145,14 +145,17 @@ public class TestFocus02SwingAWTRobot extends UITestCase { jPanel1.add(new Button("west"), BorderLayout.WEST); jPanel1.add(container1, BorderLayout.CENTER); - JFrame jFrame1 = new JFrame("Swing Parent JFrame"); + final JFrame jFrame1 = new JFrame("Swing Parent JFrame"); AWTFocusAdapter jFrame1FA = new AWTFocusAdapter("JFrame1"); jFrame1.addFocusListener(jFrame1FA); // jFrame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // equivalent to Frame, use windowClosing event! jFrame1.setContentPane(jPanel1); jFrame1.setSize(width, height); - jFrame1.setVisible(true); // from here on, we need to run modifications on EDT + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jFrame1.setVisible(true); + } } ); Assert.assertTrue(AWTRobotUtil.toFront(robot, jFrame1)); int wait=0; @@ -192,7 +195,6 @@ public class TestFocus02SwingAWTRobot extends UITestCase { System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); AWTRobotUtil.assertRequestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonNorthOuterFA); - Assert.assertTrue(AWTRobotUtil.waitForFocusCount(false, newtCanvasAWTFA)); Assert.assertEquals(true, glWindow1FA.focusGained()); Assert.assertEquals(false, buttonNorthOuterFA.focusGained()); Assert.assertEquals(true, buttonNorthOuterFA.focusLost()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java index 15151fa2c..429ef59cd 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java @@ -111,7 +111,7 @@ public class TestListenerCom01AWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java index 46748cb52..473f2f584 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java @@ -51,7 +51,11 @@ class NewtAWTReparentingKeyAdapter extends KeyAdapter { if(e.getKeyChar()=='d') { glWindow.setUndecorated(!glWindow.isUndecorated()); } else if(e.getKeyChar()=='f') { - glWindow.setFullscreen(!glWindow.isFullscreen()); + glWindow.setFullscreen(!glWindow.isFullscreen()); + } else if(e.getKeyChar()=='l') { + javax.media.nativewindow.util.Point p0 = newtCanvasAWT.getNativeWindow().getLocationOnScreen(null); + javax.media.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); + System.err.println("NewtCanvasAWT position: "+p0+", "+p1); } else if(e.getKeyChar()=='p') { new Thread() { public void run() { diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java index 7f97be649..b49cf2670 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java @@ -654,7 +654,7 @@ public class TestParenting01NEWT extends UITestCase { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); } - if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getWindow())) { + if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getDelegatedWindow())) { MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); } } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java index 674cf4a06..2040fb9b6 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java @@ -467,7 +467,7 @@ public class TestParenting01aAWT extends UITestCase { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); } - if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getWindow())) { + if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getDelegatedWindow())) { MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); } } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java index 8571609a8..d98a540ec 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java @@ -173,7 +173,7 @@ public class TestParenting01bAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java index 3b40554d2..dfd0787e7 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java @@ -228,7 +228,7 @@ public class TestParenting01cAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java index f505547d4..22ed7c6fd 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java @@ -319,7 +319,7 @@ public class TestParenting01cSwingAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java index f01468c2a..39759de9f 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java @@ -233,7 +233,7 @@ public class TestParenting02AWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java index aded8f163..8f0da4000 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java @@ -35,10 +35,10 @@ import org.junit.BeforeClass; import org.junit.Test; import java.awt.BorderLayout; +import java.awt.Button; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; -import java.awt.Label; import javax.media.opengl.*; @@ -53,28 +53,34 @@ import com.jogamp.opengl.test.junit.util.*; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; public class TestParenting03AWT extends UITestCase { - static Dimension size; + static Dimension glSize, fSize; static long durationPerTest = 800; static long waitAdd2nd = 500; static GLCapabilities glCaps; @BeforeClass public static void initClass() { - size = new Dimension(400,200); + glSize = new Dimension(400,200); + fSize = new Dimension(3*400,2*200); glCaps = new GLCapabilities(null); } @Test - public void testWindowParenting1AWTTwoNewtChilds01() throws InterruptedException, InvocationTargetException { - testWindowParenting1AWTTwoNewtChilds(); + public void testWindowParenting1AWTOneNewtChilds01() throws InterruptedException, InvocationTargetException { + testWindowParenting1AWT(false); } - public void testWindowParenting1AWTTwoNewtChilds() throws InterruptedException, InvocationTargetException { + @Test + public void testWindowParenting1AWTTwoNewtChilds01() throws InterruptedException, InvocationTargetException { + testWindowParenting1AWT(true); + } + + public void testWindowParenting1AWT(boolean use2nd) throws InterruptedException, InvocationTargetException { final Frame frame1 = new Frame("AWT Parent Frame"); GLWindow glWindow1 = GLWindow.create(glCaps); glWindow1.setUpdateFPSFrames(1, null); final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); - newtCanvasAWT1.setPreferredSize(size); + newtCanvasAWT1.setPreferredSize(glSize); GLEventListener demo1 = new GearsES2(1); setDemoFields(demo1, glWindow1, false); @@ -83,7 +89,6 @@ public class TestParenting03AWT extends UITestCase { GLAnimatorControl animator1 = new Animator(glWindow1); animator1.start(); - final boolean use2nd = true; GLWindow glWindow2 = null; NewtCanvasAWT newtCanvasAWT2 = null; GLAnimatorControl animator2 = null; @@ -91,7 +96,7 @@ public class TestParenting03AWT extends UITestCase { glWindow2 = GLWindow.create(glCaps); glWindow2.setUpdateFPSFrames(1, null); newtCanvasAWT2 = new NewtCanvasAWT(glWindow2); - newtCanvasAWT2.setPreferredSize(size); + newtCanvasAWT2.setPreferredSize(glSize); GLEventListener demo2 = new GearsES2(1); setDemoFields(demo2, glWindow2, false); @@ -103,10 +108,10 @@ public class TestParenting03AWT extends UITestCase { final Container cont1 = new Container(); cont1.setLayout(new BorderLayout()); - cont1.add(new Label("iNORTH"), BorderLayout.NORTH); - cont1.add(new Label("iSOUTH"), BorderLayout.SOUTH); - cont1.add(new Label("iEAST"), BorderLayout.EAST); - cont1.add(new Label("iWEST"), BorderLayout.WEST); + cont1.add(new Button("NORTH"), BorderLayout.NORTH); + cont1.add(new Button("SOUTH"), BorderLayout.SOUTH); + cont1.add(new Button("EAST"), BorderLayout.EAST); + cont1.add(new Button("WEST"), BorderLayout.WEST); cont1.add(newtCanvasAWT1, BorderLayout.CENTER); System.err.println("******* Cont1 setVisible"); cont1.setVisible(true); @@ -114,34 +119,31 @@ public class TestParenting03AWT extends UITestCase { final Container cont2 = new Container(); cont2.setLayout(new BorderLayout()); if(use2nd) { - cont2.add(new Label("iNORTH"), BorderLayout.NORTH); - cont2.add(new Label("iSOUTH"), BorderLayout.SOUTH); - cont2.add(new Label("iEAST"), BorderLayout.EAST); - cont2.add(new Label("iWEST"), BorderLayout.WEST); + cont2.add(new Button("north"), BorderLayout.NORTH); + cont2.add(new Button("sourth"), BorderLayout.SOUTH); + cont2.add(new Button("east"), BorderLayout.EAST); + cont2.add(new Button("west"), BorderLayout.WEST); cont2.add(newtCanvasAWT2, BorderLayout.CENTER); } System.err.println("******* Cont2 setVisible"); cont2.setVisible(true); frame1.setLayout(new BorderLayout()); - frame1.add(new Label("NORTH"), BorderLayout.NORTH); - frame1.add(new Label("CENTER"), BorderLayout.CENTER); - frame1.add(new Label("SOUTH"), BorderLayout.SOUTH); + frame1.add(new Button("NORTH"), BorderLayout.NORTH); + frame1.add(new Button("CENTER"), BorderLayout.CENTER); + frame1.add(new Button("SOUTH"), BorderLayout.SOUTH); frame1.add(cont1, BorderLayout.EAST); frame1.setLocation(0, 0); - frame1.setSize((int)size.getWidth()*3, (int)size.getHeight()*2); + frame1.setSize(fSize); javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { System.err.println("******* Frame setVisible"); + frame1.validate(); frame1.setVisible(true); }}); Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); - if(use2nd) { - Assert.assertEquals(newtCanvasAWT2.getNativeWindow(),glWindow2.getParent()); - } - Assert.assertEquals(true, animator1.isAnimating()); Assert.assertEquals(false, animator1.isPaused()); Assert.assertNotNull(animator1.getThread()); @@ -150,15 +152,17 @@ public class TestParenting03AWT extends UITestCase { Assert.assertEquals(true, animator2.isAnimating()); Assert.assertEquals(false, animator2.isPaused()); Assert.assertNotNull(animator2.getThread()); - } - Thread.sleep(waitAdd2nd); + Thread.sleep(waitAdd2nd); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.add(cont2, BorderLayout.WEST); + frame1.validate(); + }}); + Assert.assertEquals(newtCanvasAWT2.getNativeWindow(),glWindow2.getParent()); + } - javax.swing.SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - frame1.add(cont2, BorderLayout.WEST); - frame1.validate(); - }}); Thread.sleep(durationPerTest); @@ -187,7 +191,7 @@ public class TestParenting03AWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java new file mode 100644 index 000000000..b23c17022 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java @@ -0,0 +1,334 @@ +/** + * 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 com.jogamp.opengl.test.junit.newt.parenting; + +import java.lang.reflect.*; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.awt.AWTException; +import java.awt.AWTKeyStroke; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; + +import javax.media.opengl.*; + +import com.jogamp.opengl.util.Animator; +import com.jogamp.newt.*; +import com.jogamp.newt.opengl.*; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; + +import java.io.IOException; + +import jogamp.newt.driver.DriverClearFocus; + +import com.jogamp.opengl.test.junit.util.*; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; + +public class TestParentingFocusTraversal01AWT extends UITestCase { + static Dimension glSize, fSize; + static int numFocus = 8; + static long durationPerTest = numFocus * 100; + static GLCapabilities glCaps; + static boolean manual = false; + + @BeforeClass + public static void initClass() { + glSize = new Dimension(200,200); + fSize = new Dimension(300,300); + glCaps = new GLCapabilities(null); + } + + @Test + public void testWindowParentingAWTFocusTraversal01Onscreen() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(true); + } + + @Test + public void testWindowParentingAWTFocusTraversal02Offscreen() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(false); + } + + public void testWindowParentingAWTFocusTraversal(boolean onscreen) throws InterruptedException, InvocationTargetException, AWTException { + Robot robot = new Robot(); + + // Bug 4908075 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4908075 + // Bug 6463168 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6463168 + { + final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + final Set<AWTKeyStroke> bwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + final AWTKeyStroke newBack = AWTKeyStroke.getAWTKeyStroke(java.awt.event.KeyEvent.VK_BACK_SPACE, 0, false); + Assert.assertNotNull(newBack); + final Set<AWTKeyStroke> bwdKeys2 = new HashSet<AWTKeyStroke>(bwdKeys); + bwdKeys2.add(newBack); + kfm.setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, bwdKeys2); + } + { + final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + final Set<AWTKeyStroke> fwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + final Set<AWTKeyStroke> bwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + Iterator<AWTKeyStroke> iter; + for(iter = fwdKeys.iterator(); iter.hasNext(); ) { + System.err.println("FTKL.fwd-keys: "+iter.next()); + } + for(iter = bwdKeys.iterator(); iter.hasNext(); ) { + System.err.println("FTKL.bwd-keys: "+iter.next()); + } + } + + final Frame frame1 = new Frame("AWT Parent Frame"); + final Button cWest = new Button("WEST"); + final Button cEast = new Button("EAST"); + final GLWindow glWindow1 = GLWindow.create(glCaps); + glWindow1.setUpdateFPSFrames(1, null); + final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); + newtCanvasAWT1.setPreferredSize(glSize); + newtCanvasAWT1.setShallUseOffscreenLayer(!onscreen); + newtCanvasAWT1.setFocusable(true); + + // Test FocusAdapter + NEWTFocusAdapter glWindow1FA = new NEWTFocusAdapter("GLWindow1"); + glWindow1.addWindowListener(glWindow1FA); + AWTFocusAdapter bWestFA = new AWTFocusAdapter("WEST"); + cWest.addFocusListener(bWestFA); + AWTFocusAdapter bEastFA = new AWTFocusAdapter("EAST"); + cEast.addFocusListener(bEastFA); + + // Test KeyAdapter + NEWTKeyAdapter glWindow1KA = new NEWTKeyAdapter("GLWindow1"); + glWindow1.addKeyListener(glWindow1KA); + AWTKeyAdapter bWestKA = new AWTKeyAdapter("West"); + cWest.addKeyListener(bWestKA); + AWTKeyAdapter bEastKA = new AWTKeyAdapter("East"); + cEast.addKeyListener(bEastKA); + + // demo .. + GLEventListener demo1 = new GearsES2(1); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); + glWindow1.addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { + if(e.getKeyChar()=='c') { + System.err.println("Focus Clear"); + if(glWindow1.getDelegatedWindow() instanceof DriverClearFocus) { + ((DriverClearFocus)glWindow1.getDelegatedWindow()).clearFocus(); + } + } else if(e.getKeyChar()=='e') { + System.err.println("Focus East"); + try { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + cEast.requestFocusInWindow(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + } else if(e.getKeyChar()=='w') { + System.err.println("Focus West"); + try { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + cWest.requestFocusInWindow(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + }); + GLAnimatorControl animator1 = new Animator(glWindow1); + animator1.start(); + + // make frame + frame1.setLayout(new BorderLayout()); + frame1.setLayout(new BorderLayout()); + frame1.add(cWest, BorderLayout.WEST); + frame1.add(newtCanvasAWT1, BorderLayout.CENTER); + frame1.add(cEast, BorderLayout.EAST); + + frame1.setLocation(0, 0); + frame1.setSize(fSize); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.validate(); + frame1.setVisible(true); + }}); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glWindow1, true)); + Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); + + Assert.assertEquals(true, animator1.isAnimating()); + Assert.assertEquals(false, animator1.isPaused()); + Assert.assertNotNull(animator1.getThread()); + + if(manual) { + Thread.sleep(durationPerTest); + } else { + // + // initial focus on bWest + // + AWTRobotUtil.assertRequestFocusAndWait(robot, cWest, cWest, bWestFA, null); + Assert.assertEquals(true, bWestFA.focusGained()); + Thread.sleep(durationPerTest/numFocus); + + // + // forth + // + + // bWest -> glWin + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, cWest, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // glWin -> bEast + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, glWindow1, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cEast, bEastFA, glWindow1FA)); + Assert.assertEquals(true, bEastFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // + // back (using custom back traversal key 'backspace') + // + // bEast -> glWin + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, cEast, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bEastFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bEastFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, glWindow1, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cWest, bWestFA, glWindow1FA)); + Assert.assertEquals(true, bWestFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct AWT request focus + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + newtCanvasAWT1.requestFocus(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct AWT request focus + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + cWest.requestFocus(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cWest, bWestFA, glWindow1FA)); + Assert.assertEquals(true, bWestFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct NEWT request focus + glWindow1.requestFocus(); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + } + + animator1.stop(); + Assert.assertEquals(false, animator1.isAnimating()); + Assert.assertEquals(false, animator1.isPaused()); + Assert.assertEquals(null, animator1.getThread()); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.dispose(); + } } ); + glWindow1.destroy(); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getDelegatedWindow(); + if(debug) { + MiscUtils.setFieldIfExists(demo, "glDebug", true); + MiscUtils.setFieldIfExists(demo, "glTrace", true); + } + if(!MiscUtils.setFieldIfExists(demo, "window", window)) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } else if(args[i].equals("-manual")) { + manual = true; + } + } + String tstname = TestParentingFocusTraversal01AWT.class.getName(); + /* + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + tstname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); */ + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01AWT.java new file mode 100644 index 000000000..fb2f7342e --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01AWT.java @@ -0,0 +1,225 @@ +/** + * 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 com.jogamp.opengl.test.junit.newt.parenting; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.awt.GLCanvas; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.newt.Window; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestParentingOffscreenLayer01AWT extends UITestCase { + static Dimension frameSize; + static Dimension preferredGLSize; + static Dimension minGLSize; + static long durationPerTest = 800; + + @BeforeClass + public static void initClass() { + frameSize = new Dimension(500,300); + preferredGLSize = new Dimension(400,200); + minGLSize = new Dimension(200,100); + } + + private void setupFrameAndShow(final Frame f, java.awt.Component comp) throws InterruptedException, InvocationTargetException { + + Container c = new Container(); + c.setLayout(new BorderLayout()); + c.add(new Button("north"), BorderLayout.NORTH); + c.add(new Button("south"), BorderLayout.SOUTH); + c.add(new Button("east"), BorderLayout.EAST); + c.add(new Button("west"), BorderLayout.WEST); + c.add(comp, BorderLayout.CENTER); + + f.setLayout(new BorderLayout()); + f.add(new Button("NORTH"), BorderLayout.NORTH); + f.add(new Button("SOUTH"), BorderLayout.SOUTH); + f.add(new Button("EAST"), BorderLayout.EAST); + f.add(new Button("WEST"), BorderLayout.WEST); + f.add(c, BorderLayout.CENTER); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + // f.pack(); + f.validate(); + f.setVisible(true); + }}); + } + private void end(GLAnimatorControl actrl, final Frame f, Window w) throws InterruptedException, InvocationTargetException { + actrl.stop(); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + f.dispose(); + } } ); + if(null != w) { + w.destroy(); + } + } + + // @Test + public void testOffscreenLayerPath0_GLCanvas() throws InterruptedException, InvocationTargetException { + final Frame frame1 = new Frame("AWT Parent Frame"); + + GLCapabilities glCaps = new GLCapabilities(null); + final GLCanvas glc = new GLCanvas(glCaps); + glc.setPreferredSize(preferredGLSize); + glc.setMinimumSize(minGLSize); + + GLEventListener demo1 = new GearsES2(1); + glc.addGLEventListener(demo1); + + frame1.setSize(frameSize); + setupFrameAndShow(frame1, glc); + + GLAnimatorControl animator1 = new Animator(glc); + animator1.start(); + + Thread.sleep(durationPerTest); + end(animator1, frame1, null); + } + + @Test + public void testOnscreenLayer() throws InterruptedException, InvocationTargetException { + testOffscreenLayerPath1_Impl(false, false); + } + + @Test + public void testOffscreenLayerPath1_NewtOffscreen() throws InterruptedException, InvocationTargetException { + testOffscreenLayerPath1_Impl(true, true); + } + + @Test + public void testOffscreenLayerPath1_NewtOnscreen() throws InterruptedException, InvocationTargetException { + testOffscreenLayerPath1_Impl(true, false); + } + + private void testOffscreenLayerPath1_Impl(boolean offscreenLayer, boolean newtOffscreenClass) throws InterruptedException, InvocationTargetException { + final Frame frame1 = new Frame("AWT Parent Frame"); + + GLCapabilities glCaps = new GLCapabilities(null); + if(newtOffscreenClass) { + glCaps.setOnscreen(false); + glCaps.setPBuffer(true); + } + + GLWindow glWindow1 = GLWindow.create(glCaps); + + final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); + newtCanvasAWT1.setShallUseOffscreenLayer(offscreenLayer); // trigger offscreen layer - if supported + newtCanvasAWT1.setPreferredSize(preferredGLSize); + newtCanvasAWT1.setMinimumSize(minGLSize); + + GLEventListener demo1 = new GearsES2(1); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); + + frame1.setSize(frameSize); + setupFrameAndShow(frame1, newtCanvasAWT1); + Assert.assertTrue(glWindow1.isNativeValid()); + Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); + + GLAnimatorControl animator1 = new Animator(glWindow1); + animator1.start(); + + Thread.sleep(durationPerTest); + end(animator1, frame1, glWindow1); + } + + // @Test + public void testOffscreenLayerPath2_NewtOffscreen() throws InterruptedException, InvocationTargetException { + testOffscreenLayerPath2_Impl(true); + } + + private void testOffscreenLayerPath2_Impl(boolean newtOffscreenClass) throws InterruptedException, InvocationTargetException { + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getDelegatedWindow(); + if(debug) { + MiscUtils.setFieldIfExists(demo, "glDebug", true); + MiscUtils.setFieldIfExists(demo, "glTrace", true); + } + if(!MiscUtils.setFieldIfExists(demo, "window", window)) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } + } + String tstname = TestParentingOffscreenLayer01AWT.class.getName(); + /* + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + tstname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); */ + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java index be812e6aa..86a76f9ff 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java @@ -157,7 +157,7 @@ public class TestTranslucentParentingAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java index 7df8645de..a27bdd7a2 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java @@ -67,7 +67,7 @@ public class AWTRobotUtil { int x0, y0; if(null!=comp) { - java.awt.Point p0 = comp.getLocationOnScreen(); + java.awt.Point p0 = comp.getLocationOnScreen(); java.awt.Rectangle r0 = comp.getBounds(); if( onTitleBarIfWindow && comp instanceof java.awt.Window) { java.awt.Window window = (java.awt.Window) comp; @@ -78,7 +78,7 @@ public class AWTRobotUtil { } x0 = (int) ( p0.getX() + r0.getWidth() / 2.0 + .5 ) ; } else { - javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); + javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); if( onTitleBarIfWindow ) { javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); p0.translate(win.getWidth()/2, insets.getTopHeight()/2); @@ -102,6 +102,9 @@ public class AWTRobotUtil { public static boolean toFront(Robot robot, final java.awt.Window window) throws AWTException, InterruptedException, InvocationTargetException { + AWTWindowFocusAdapter winFA = new AWTWindowFocusAdapter("window"); + window.addWindowFocusListener(winFA); + if(null == robot) { robot = new Robot(); robot.setAutoWaitForIdle(true); @@ -119,11 +122,11 @@ public class AWTRobotUtil { }}); robot.delay(ROBOT_DELAY); - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); int wait; - for (wait=0; wait<POLL_DIVIDER && window != kfm.getFocusedWindow(); wait++) { + for (wait=0; wait<POLL_DIVIDER && !winFA.focusGained(); wait++) { Thread.sleep(TIME_SLICE); } + window.removeWindowFocusListener(winFA); return wait<POLL_DIVIDER; } @@ -280,8 +283,8 @@ public class AWTRobotUtil { Assert.assertTrue("Did not gain focus", hasFocus); } - static int keyType(int i, Robot robot, int keyCode, - Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException + public static int keyType(int i, Robot robot, int keyCode, + Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException { int tc = 0; int j; @@ -293,13 +296,13 @@ public class AWTRobotUtil { if(DEBUG) { System.err.println(i+":"+j+" KC1.0: "+counter+" - regain focus"); } requestFocus(null, obj); } - final int c0 = counter.getCount(); + final int c0 = null!=counter ? counter.getCount() : 0; if(DEBUG) { System.err.println(i+":"+j+" KC1.1: "+counter); } robot.waitForIdle(); robot.keyPress(keyCode); robot.keyRelease(keyCode); if(DEBUG) { System.err.println(i+":"+j+" KC1.2: "+counter); } - tc = counter.getCount() - c0; + tc = ( null!=counter ? counter.getCount() : 1 ) - c0; for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) { robot.delay(TIME_SLICE); tc = counter.getCount() - c0; @@ -355,13 +358,13 @@ public class AWTRobotUtil { if(DEBUG) { System.err.println(i+":"+j+" MC1.0: "+counter+" - regain focus"); } requestFocus(null, obj); } - final int c0 = counter.getCount(); + final int c0 = null != counter ? counter.getCount() : 0; if(DEBUG) { System.err.println(i+":"+j+" MC1.1: "+counter); } robot.waitForIdle(); robot.mousePress(mouseButton); robot.mouseRelease(mouseButton); if(DEBUG) { System.err.println(i+":"+j+" MC1.2: "+counter); } - tc = counter.getCount() - c0; + tc = ( null != counter ? counter.getCount() : 1 ) - c0; for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) { robot.delay(TIME_SLICE); tc = counter.getCount() - c0; diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java new file mode 100644 index 000000000..16aacd2fd --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java @@ -0,0 +1,71 @@ +/** + * 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 com.jogamp.opengl.test.junit.util; + +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +public class AWTWindowFocusAdapter implements FocusEventCountAdapter, WindowFocusListener { + + String prefix; + int focusCount; + + public AWTWindowFocusAdapter(String prefix) { + this.prefix = prefix; + reset(); + } + + public boolean focusLost() { + return focusCount<0; + } + + public boolean focusGained() { + return focusCount>0; + } + + public void reset() { + focusCount = 0; + } + + /* @Override */ + public void windowGainedFocus(WindowEvent e) { + if(focusCount<0) { focusCount=0; } + focusCount++; + System.err.println("FOCUS AWT GAINED (Window) [fc "+focusCount+"]: "+prefix+", "+e); + } + + /* @Override */ + public void windowLostFocus(WindowEvent e) { + if(focusCount>0) { focusCount=0; } + focusCount--; + System.err.println("FOCUS AWT LOST (Window) [fc "+focusCount+"]: "+prefix+", "+e); + } + + public String toString() { return prefix+"[focusCount "+focusCount +"]"; } +} diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java index 6a6cf390f..c74d2eaa7 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java +++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java @@ -78,6 +78,7 @@ public class NEWTGLContext { Assert.assertNotNull(drawable); drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); GLContext context = drawable.createContext(null); Assert.assertNotNull(context); diff --git a/src/test/jogamp/newt/WindowImplAccess.java b/src/test/jogamp/newt/WindowImplAccess.java index 76d0dc050..e8be5f68a 100644 --- a/src/test/jogamp/newt/WindowImplAccess.java +++ b/src/test/jogamp/newt/WindowImplAccess.java @@ -29,26 +29,16 @@ package jogamp.newt; import com.jogamp.newt.Window; -import com.jogamp.newt.opengl.GLWindow; /** * Allows access to protected methods of WindowImpl */ public class WindowImplAccess { public static final void windowDestroyNotify(Window win) { - WindowImpl winImpl = null; - if(win instanceof GLWindow) { - GLWindow glwin = (GLWindow) win; - winImpl = (WindowImpl) glwin.getWindow(); - } else if(win instanceof WindowImpl) { - winImpl = (WindowImpl) win; - } else { - throw new RuntimeException("Given Window not a GLWindow, not WindowImpl, but "+win.getClass()); - } - final WindowImpl winImplF = winImpl; - winImplF.runOnEDTIfAvail(true, new Runnable() { + final WindowImpl winImpl = (WindowImpl) win.getDelegatedWindow(); + winImpl.runOnEDTIfAvail(true, new Runnable() { public void run() { - winImplF.windowDestroyNotify(); + winImpl.windowDestroyNotify(); } }); } |