diff options
author | Sven Gothel <[email protected]> | 2010-05-28 16:53:08 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-05-28 16:53:08 +0200 |
commit | 811bd23ed37e392abb349f850a0b1dac635d021e (patch) | |
tree | c4faf8f5728eabd0fd9ed8a28816ab361984a9b7 | |
parent | c787f50d77e2491eb0d8201d534a6fa4885a929e (diff) |
NEWT: Fix AWT Parenting ; Multithreading Issues ; Semantics: destroy(), .. ; Misc.
Due to incapabilities of the previous AWT/NEWT reparenting
the implementation and spec had to be changed to support this feature.
See the first 2 comments below.
- Tested on GNU/Linux (OK), Windows (a few bugs left)
-
TODO:
- Clarify the size/layout issue, ie who is responsible etc
In the test, incl AWT/NEWT, we set the size on the GLWindow
and ie pack the AWT Frame.
- Fix remaining [Windows] bugs ..
- Fix/Implement MacOSX port ..
Fix AWT/NEWT reparenting:
===========================
- Now NewtFactory's createWindow() method for parenting handles NativeWindow only
and is no more responsible for creating a child window upon an AWT Component.
See class com.jogamp.newt.awt.NewtCanvasAWT for NEWT/AWT parenting.
- New com.jogamp.newt.awt.NewtCanvasAWT, responsible for handling
AWT's reparent events via addNotify/removeNotify.
Reparenting is implemented via the new NEWT Window's reparentWindow() method.
Also sets the background erase to false, if supported.
- Fix zero size semantics in Window (setSize/setVisible)
Since a zero size window is not supported by many compoenent (Windowing system, OpenGL, ..)
we use the visibility methodology to not show a 0x0 window. See Javadoc.
AWT components may start with zero size.
- New NEWT Window: reparentWindow(NativeWindow newParent, Screen newScreen)
Allowing to change the parent of a window. Similar with the fullscreen toggle,
but without size/position change.
Native reparenting allows to keep alive the native
window while changing the container, hence it is preferred to a destroy/create cycle.
To benefit from the native reparenting, a NEWT implementation has to implement
'protected boolean reparentWindowImpl(long newWindowHandle)'
and return true, otherwise reparenting will be 'emulated' via
the expensive destroy/create cycle.
- NEWT's Window references all of it's children, if any
- NEWT's Window propagates setVisible/destroy actions to it's children.
- Fix NEWT's destroy() semantics.
A call of destroy() or destroy(false) shall only result in the destruction of the
native window (handle) nothing more. A subsequent setVisible(true) shall allow
the complete recreation of the Window into a usable state.
A call of destroy(true) destroys all resources the Window holds,
may include Screen/Display and OpenGL resources in case of GLWindow.
This is necessary to allow proper reparenting, where a native window may become
destroyed, but should be recreated via setVisible(true) later on.
- Fix NEWT set[Size|Position|Fullscreen|Visible] synchronization.
Use a recursive lock instead of the Window instance, otherwise arbitrary Window access
via AWT's EDT, NEWT's EDT or other threads can block.
Also removed a use pattern like:
key.lock()
try {
EDT.invoke(action());
} finally {
key.unlock();
}
Where action() itself uses the same lock object (here key), the result is a deadlock.
NativeWindow Changes:
======================
- We can use XInitThreads() now (concurrent threading support)
in combination with AWT.
Might have been some async in our NEWT locking in regards to AWT (sync()),
and the X11 Display changes made in c787f50d77e2491eb0d8201d534a6fa4885a929e.
- NativeWindow's window handle is _not_ transient like surface handle,
fixed documentation.
JOGL Changes:
=============
- New 'isRealized()' method in GLDrawable.
-
Misc Fixes
============
- Fix NEWT set[Size|Position|Fullscreen|Visible] duplicate code
Due to pure abstract signatures, the set[Size|Position|Fullscreen|Visible]
implementations of X11, OSX, .. contained duplicate code and state handling (size, pos, ..).
These are now decoupled, ie generic set[Size|Position|Fullscreen|Visible] implementations
calling simple set[Size|Position|Fullscreen|Visible]Impl implementations.
- Fix NEWT: Renamed setAutoDrawableClient(boolean) to setHandleDestroyNotify(boolean)
The semantic of
setAutoDrawableClient(boolean) defaults to false
was too complicated and specific, hence changed to
setHandleDestroyNotify(boolean) defaults to true
since its more clear and the name refers the window itself..
- Fix NEWT: Removed GLWindow's unused global window list
- Fix NEWT: Remove Window's unused event mask
- Rename com.jogamp.newt.impl.awt.AWTNewtFactory -> com.jogamp.newt.awt.NewtFactoryAWT
44 files changed, 2688 insertions, 1048 deletions
diff --git a/make/build-newt.xml b/make/build-newt.xml index 08c0f308b..2cb848588 100644 --- a/make/build-newt.xml +++ b/make/build-newt.xml @@ -90,7 +90,7 @@ value="com/jogamp/newt/*, com/jogamp/newt/event/*, com/jogamp/newt/util/*, com/jogamp/newt/impl/*"/> <property name="java.part.awt" - value="com/jogamp/newt/impl/awt/*, com/jogamp/newt/event/awt/*"/> + value="com/jogamp/newt/impl/awt/*, com/jogamp/newt/awt/*, com/jogamp/newt/event/awt/*"/> <property name="java.part.x11" value="com/jogamp/newt/impl/x11/*"/> diff --git a/make/scripts/java-run-all.sh b/make/scripts/java-run-all.sh index 8c50d0933..0e5be242a 100755 --- a/make/scripts/java-run-all.sh +++ b/make/scripts/java-run-all.sh @@ -35,6 +35,7 @@ uname -a | grep -i Darwin && MOSX=1 # D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all -Djogl.debug.GLSLState" # D_ARGS="-Dnativewindow.debug.X11Util=true -Djogl.debug.GLDrawableFactory=true" # D_ARGS="-Dnativewindow.debug.X11Util=true" +# D_ARGS="-Dnewt.debug=all -Dnativewindow.debug=all" # D_ARGS="-Dnewt.debug=all" # D_ARGS="-Dnewt.debug.Window" # D_ARGS="-Djogl.debug=all" diff --git a/make/scripts/java-run-newt.sh b/make/scripts/java-run-newt.sh index 94f77143f..796e22da4 100755 --- a/make/scripts/java-run-newt.sh +++ b/make/scripts/java-run-newt.sh @@ -39,5 +39,6 @@ fi # D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all -Djogl.debug.GLSLState" # D_ARGS="-Dnativewindow.debug.X11Util=true -Djogl.debug.GLDrawableFactory=true" # D_ARGS="-Dnativewindow.debug.X11Util=true" +# D_ARGS="-Dnewt.debug=all" java $X_ARGS -Djava.awt.headless=true $D_ARGS com.jogamp.newt.util.MainThread $* 2>&1 | tee java-run-newt.log diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableImpl.java index 2fef8fd80..62b89a13e 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableImpl.java @@ -124,7 +124,7 @@ public abstract class GLDrawableImpl implements GLDrawable { } protected abstract void setRealizedImpl(); - public boolean getRealized() { + public boolean isRealized() { return realized; } @@ -153,7 +153,7 @@ public abstract class GLDrawableImpl implements GLDrawable { } public String toString() { - return getClass().getName()+"[Realized "+getRealized()+ + return getClass().getName()+"[Realized "+isRealized()+ ",\n\tFactory "+getFactory()+ ",\n\tWindow "+getNativeWindow()+"]"; } diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java index dd8d980a6..1da19663a 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLPbufferImpl.java @@ -86,6 +86,10 @@ public class GLPbufferImpl implements GLPbuffer { public void setRealized(boolean realized) { } + public boolean isRealized() { + return true; + } + public void setSize(int width, int height) { // FIXME throw new GLException("Not yet implemented"); diff --git a/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawable.java b/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawable.java index dcfe06bdc..2e24abcec 100755 --- a/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawable.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawable.java @@ -213,7 +213,7 @@ public abstract class EGLDrawable extends GLDrawableImpl { } public String toString() { - return getClass().getName()+"[realized "+getRealized()+ + return getClass().getName()+"[realized "+isRealized()+ ",\n\tfactory "+getFactory()+ ",\n\twindow "+getNativeWindow()+ ",\n\teglSurface 0x"+Long.toHexString(eglSurface)+ diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java index 0cde24ff9..469cc5170 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java @@ -123,6 +123,9 @@ public interface GLDrawable { */ public void setRealized(boolean realized); + /** @return true if this drawable is realized, otherwise false */ + public boolean isRealized(); + /** Returns the current width of this GLDrawable. */ public int getWidth(); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 53e79b8d9..9932f0cf9 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -283,6 +283,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { public void setRealized(boolean realized) { } + public boolean isRealized() { + return ( null != drawable ) ? drawable.isRealized() : false; + } + private Object closingListener = null; private Object closingListenerLock = new Object(); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index e8de00629..eb8c68263 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -379,6 +379,10 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable { public void setRealized(boolean realized) { } + public boolean isRealized() { + return isInitialized; + } + public void setContext(GLContext ctx) { if (backend == null) { return; diff --git a/src/junit/com/jogamp/test/junit/newt/KeyAction.java b/src/junit/com/jogamp/test/junit/newt/KeyAction.java index 29b3d2ee2..3ca12a840 100644 --- a/src/junit/com/jogamp/test/junit/newt/KeyAction.java +++ b/src/junit/com/jogamp/test/junit/newt/KeyAction.java @@ -33,7 +33,6 @@ package com.jogamp.test.junit.newt; -import com.jogamp.opengl.util.Animator; import com.jogamp.newt.event.*; class KeyAction extends KeyAdapter { diff --git a/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java new file mode 100755 index 000000000..b96e74182 --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2010 Sven Gothel. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name Sven Gothel or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SVEN GOTHEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.test.junit.newt; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Test; + +import javax.media.nativewindow.*; +import javax.media.opengl.*; + +import com.jogamp.opengl.util.Animator; +import com.jogamp.newt.*; +import com.jogamp.newt.opengl.*; +import java.io.IOException; + +import com.jogamp.test.junit.util.MiscUtils; +import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; + +public class TestGLWindows01NEWT { + static GLProfile glp; + static int width, height; + static long duration = 100; // ms + + @BeforeClass + public static void initClass() { + width = 640; + height = 480; + glp = GLProfile.getDefault(); + } + + static GLWindow createWindow(Screen screen, GLCapabilities caps, int width, int height, boolean onscreen, boolean undecorated) { + Assert.assertNotNull(caps); + caps.setOnscreen(onscreen); + // System.out.println("Requested: "+caps); + + // + // Create native windowing resources .. X11/Win/OSX + // + GLWindow glWindow; + if(null!=screen) { + Window window = NewtFactory.createWindow(screen, caps, onscreen && undecorated); + Assert.assertNotNull(window); + glWindow = GLWindow.create(window); + } else { + glWindow = GLWindow.create(caps, onscreen && undecorated); + } + Assert.assertNotNull(glWindow); + Assert.assertEquals(false,glWindow.isNativeWindowValid()); + glWindow.setSize(width, height); + Assert.assertEquals(false,glWindow.isVisible()); + glWindow.setVisible(true); + Assert.assertEquals(true,glWindow.isVisible()); + Assert.assertEquals(true,glWindow.isNativeWindowValid()); + // Assert.assertEquals(width,glWindow.getWidth()); + // Assert.assertEquals(height,glWindow.getHeight()); + // System.out.println("Created: "+glWindow); + + // + // Create native OpenGL resources .. XGL/WGL/CGL .. + // equivalent to GLAutoDrawable methods: setVisible(true) + // + caps = (GLCapabilities) glWindow.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + Assert.assertNotNull(caps); + Assert.assertTrue(caps.getGreenBits()>5); + Assert.assertTrue(caps.getBlueBits()>5); + Assert.assertTrue(caps.getRedBits()>5); + Assert.assertEquals(caps.isOnscreen(),onscreen); + + GLEventListener demo = new Gears(); + setDemoFields(demo, glWindow); + glWindow.addGLEventListener(demo); + + return glWindow; + } + + static void destroyWindow(GLWindow glWindow, boolean deep) { + if(null!=glWindow) { + glWindow.destroy(deep); + } + } + + @Test + public void testWindowNativeRecreate01Simple() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + GLWindow window = createWindow(null, caps, width, height, true /* onscreen */, false /* undecorated */); + + window.display(); + window.destroy(); + Assert.assertEquals(false,window.isNativeWindowValid()); + Assert.assertEquals(true,window.isVisible()); + + window.display(); + Assert.assertEquals(true,window.isNativeWindowValid()); + + Animator animator = new Animator(window); + animator.start(); + while(animator.isAnimating() && animator.getDuration()<duration) { + Thread.sleep(100); + } + animator.stop(); + destroyWindow(window, true); + } + + @Test + public void testWindowDecor01Simple() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + GLWindow window = createWindow(null, caps, width, height, true /* onscreen */, false /* undecorated */); + Animator animator = new Animator(window); + animator.start(); + while(animator.isAnimating() && animator.getDuration()<duration) { + Thread.sleep(100); + } + animator.stop(); + destroyWindow(window, true); + } + + @Test + public void testWindowDecor02DestroyWinTwiceA() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + GLWindow window = createWindow(null, caps, width, height, true /* onscreen */, false /* undecorated */); + Animator animator = new Animator(window); + animator.start(); + while(animator.isAnimating() && animator.getDuration()<duration) { + Thread.sleep(100); + } + animator.stop(); + destroyWindow(window, false); + destroyWindow(window, true); + } + + @Test + public void testWindowDecor03TwoWin() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + Display display = NewtFactory.createDisplay(null); // local display + Assert.assertNotNull(display); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + Assert.assertNotNull(screen); + + GLWindow window1 = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); + GLWindow window2 = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); + Animator animator1 = new Animator(window1); + animator1.start(); + Animator animator2 = new Animator(window2); + animator2.start(); + while(animator1.isAnimating() && animator1.getDuration()<duration) { + Thread.sleep(100); + } + animator2.stop(); + animator1.stop(); + destroyWindow(window2, false); + destroyWindow(window1, true); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getInnerWindow())) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + public static void main(String args[]) throws IOException { + String tstname = TestGLWindows01NEWT.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" } ); + } + +} diff --git a/src/junit/com/jogamp/test/junit/newt/TestParenting01AWT.java b/src/junit/com/jogamp/test/junit/newt/TestParenting01AWT.java index 2c0dc31c1..39bd84e75 100755 --- a/src/junit/com/jogamp/test/junit/newt/TestParenting01AWT.java +++ b/src/junit/com/jogamp/test/junit/newt/TestParenting01AWT.java @@ -47,15 +47,17 @@ import org.junit.Test; import java.awt.Button; import java.awt.BorderLayout; import java.awt.Canvas; -import java.awt.Component; import java.awt.Frame; +import java.awt.Dimension; import javax.media.opengl.*; import javax.media.nativewindow.*; +import com.jogamp.opengl.util.Animator; import com.jogamp.newt.*; import com.jogamp.newt.event.*; import com.jogamp.newt.opengl.*; +import com.jogamp.newt.awt.NewtCanvasAWT; import java.io.IOException; @@ -66,124 +68,293 @@ import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; public class TestParenting01AWT { static int width, height; static long durationPerTest = 500; + static long waitReparent = 0; + static GLCapabilities glCaps; @BeforeClass public static void initClass() { width = 640; height = 480; + glCaps = new GLCapabilities(null); } @Test - public void testWindowParenting01NewtChildOnAWTParentLayouted() throws InterruptedException { - runNewtChildOnAWTParent(true, false); - } + public void testWindowParenting01CreateVisibleDestroy1() throws InterruptedException { + int x = 0; + int y = 0; - @Test - public void testWindowParenting02NewtChildOnAWTParentLayoutedDef() throws InterruptedException { - runNewtChildOnAWTParent(true, true); - } + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); - @Test - public void testWindowParenting03NewtChildOnAWTParentDirect() throws InterruptedException { - runNewtChildOnAWTParent(false, false); + GLWindow glWindow1 = GLWindow.create(glCaps); + Assert.assertNotNull(glWindow1); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); + glWindow1.setTitle("testWindowParenting01CreateVisibleDestroy"); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.setSize(600, 300); + + NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); + Assert.assertNotNull(newtCanvasAWT); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); + + Frame frame = new Frame("AWT Parent Frame"); + Assert.assertNotNull(frame); + frame.add(newtCanvasAWT); + frame.setSize(width, height); + frame.pack(); + + // visible test + frame.setVisible(true); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + + Animator animator1 = new Animator(glWindow1); + animator1.start(); + while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) { + Thread.sleep(100); + } + animator1.stop(); + Assert.assertEquals(false, animator1.isAnimating()); + + frame.setVisible(false); + Assert.assertEquals(false, glWindow1.isDestroyed()); + + frame.setVisible(true); + Assert.assertEquals(false, glWindow1.isDestroyed()); + + frame.remove(newtCanvasAWT); + Assert.assertNull(glWindow1.getParentNativeWindow()); + Assert.assertEquals(false, glWindow1.isDestroyed()); + + frame.dispose(); + Assert.assertEquals(false, glWindow1.isDestroyed()); + + glWindow1.destroy(true); + Assert.assertEquals(true, glWindow1.isDestroyed()); } @Test - public void testWindowParenting04NewtChildOnAWTParentDirectDef() throws InterruptedException { - runNewtChildOnAWTParent(false, true); - } + public void testWindowParenting02CreateVisibleDestroy2Defered() throws InterruptedException { + int x = 0; + int y = 0; + + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); + + GLWindow glWindow1 = GLWindow.create(glCaps); + Assert.assertNotNull(glWindow1); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.setSize(600, 300); + + NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); + Assert.assertNotNull(newtCanvasAWT); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); - public void runNewtChildOnAWTParent(boolean useLayout, boolean deferredPeer) throws InterruptedException { Frame frame = new Frame("AWT Parent Frame"); Assert.assertNotNull(frame); - Component overlayedAWTComponent = null; - - if(useLayout) { - overlayedAWTComponent = new Canvas(); - - frame.setLayout(new BorderLayout()); - frame.add(new Button("North"), BorderLayout.NORTH); - frame.add(new Button("South"), BorderLayout.SOUTH); - frame.add(new Button("East"), BorderLayout.EAST); - frame.add(new Button("West"), BorderLayout.WEST); - if(!deferredPeer) { - frame.add(overlayedAWTComponent, BorderLayout.CENTER); - } + frame.setSize(width, height); + + // visible test + frame.setVisible(true); + + frame.add(newtCanvasAWT); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + frame.pack(); - } else { - overlayedAWTComponent = frame; + Animator animator1 = new Animator(glWindow1); + animator1.start(); + while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) { + Thread.sleep(100); } + animator1.stop(); + Assert.assertEquals(false, animator1.isAnimating()); + + frame.dispose(); + glWindow1.destroy(true); + } + + @Test + public void testWindowParenting03ReparentNewtWin2Top() throws InterruptedException { + int x = 0; + int y = 0; + + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); + + GLWindow glWindow1 = GLWindow.create(glCaps); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.setSize(600, 300); + + NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); - Assert.assertNotNull(overlayedAWTComponent); + Frame frame = new Frame("AWT Parent Frame"); frame.setSize(width, height); - if(!deferredPeer) { - // ensure native peers are valid and component is displayable - frame.setVisible(true); + frame.setLocation(640, 480); + frame.setVisible(true); + + frame.add(newtCanvasAWT); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + frame.pack(); + + Animator animator1 = new Animator(glWindow1); + animator1.start(); + + int state = 0; + while(animator1.isAnimating() && animator1.getDuration()<3*durationPerTest) { + Thread.sleep(durationPerTest); + switch(state) { + case 0: + glWindow1.reparentWindow(null, null); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); + break; + case 1: + glWindow1.reparentWindow(newtCanvasAWT.getNativeWindow(), null); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + break; + } + state++; } + frame.dispose(); + glWindow1.destroy(true); + } + + @Test + public void testWindowParenting04ReparentNewtWin2TopLayouted() throws InterruptedException { + int x = 0; + int y = 0; + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); - GLCapabilities caps = new GLCapabilities(null); - Assert.assertNotNull(caps); + GLWindow glWindow1 = GLWindow.create(glCaps); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.setSize(600, 300); - GLWindow glWindow = GLWindow.create(overlayedAWTComponent, caps); - Assert.assertNotNull(glWindow); - Assert.assertEquals(overlayedAWTComponent.isVisible(),glWindow.isVisible()); - if(!deferredPeer) { - Assert.assertTrue(0!=glWindow.getWindowHandle()); - } else { - Assert.assertTrue(0==glWindow.getWindowHandle()); - } - glWindow.setTitle("NEWT - CHILD"); - glWindow.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); - glWindow.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo))); + NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); + + Frame frame = new Frame("AWT Parent Frame"); + frame.setLayout(new BorderLayout()); + frame.add(new Button("North"), BorderLayout.NORTH); + frame.add(new Button("South"), BorderLayout.SOUTH); + frame.add(new Button("East"), BorderLayout.EAST); + frame.add(new Button("West"), BorderLayout.WEST); + frame.setSize(width, height); + frame.setLocation(640, 480); + frame.setVisible(true); - if(deferredPeer) { - if(useLayout) { - frame.add(overlayedAWTComponent, BorderLayout.CENTER); + frame.add(newtCanvasAWT, BorderLayout.CENTER); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + frame.pack(); + + Animator animator1 = new Animator(glWindow1); + animator1.start(); + + int state = 0; + while(animator1.isAnimating() && animator1.getDuration()<3*durationPerTest) { + Thread.sleep(durationPerTest); + switch(state) { + case 0: + glWindow1.reparentWindow(null, null); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); + break; + case 1: + glWindow1.reparentWindow(newtCanvasAWT.getNativeWindow(), null); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + break; } - frame.setVisible(true); // should have native peers after this - and all childs shall be visible! + state++; } - GLEventListener demo = new Gears(); - setDemoFields(demo, glWindow, false); - glWindow.addGLEventListener(demo); - - long duration = durationPerTest; - long step = 20; - NEWTEvent event; - - while (duration>0 && !glWindow.isDestroyed()) { - glWindow.display(); - Thread.sleep(step); - duration -= step; - - while( null != ( event = (NEWTEvent) eventFifo.get() ) ) { - Window source = (Window) event.getSource(); - if(event instanceof KeyEvent) { - KeyEvent keyEvent = (KeyEvent) event; - switch(keyEvent.getKeyChar()) { - case 'q': - glWindow.destroy(); - break; - case 'f': - source.setFullscreen(!source.isFullscreen()); - break; - } - } + frame.dispose(); + glWindow1.destroy(true); + } + + @Test + public void testWindowParenting05ReparentAWTWinHopFrame2Frame() throws InterruptedException { + int x = 0; + int y = 0; + + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); + + GLWindow glWindow1 = GLWindow.create(glCaps); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.setSize(600, 300); + + NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow1); + + Frame frame1 = new Frame("AWT Parent Frame"); + frame1.setLayout(new BorderLayout()); + frame1.add(new Button("North"), BorderLayout.NORTH); + frame1.add(new Button("South"), BorderLayout.SOUTH); + frame1.add(new Button("East"), BorderLayout.EAST); + frame1.add(new Button("West"), BorderLayout.WEST); + frame1.setSize(width, height); + frame1.setLocation(0, 0); + frame1.setVisible(true); + + Frame frame2 = new Frame("AWT Parent Frame"); + frame2.setLayout(new BorderLayout()); + frame2.add(new Button("North"), BorderLayout.NORTH); + frame2.add(new Button("South"), BorderLayout.SOUTH); + frame2.add(new Button("East"), BorderLayout.EAST); + frame2.add(new Button("West"), BorderLayout.WEST); + frame2.setSize(width, height); + frame2.setLocation(640, 480); + frame2.setVisible(true); + + frame1.add(newtCanvasAWT, BorderLayout.CENTER); + Assert.assertEquals(newtCanvasAWT.getNativeWindow(),glWindow1.getParentNativeWindow()); + frame1.pack(); + + Animator animator1 = new Animator(glWindow1); + animator1.start(); + + int state = 0; + while(animator1.isAnimating() && animator1.getDuration()<3*durationPerTest) { + Thread.sleep(durationPerTest); + switch(state) { + case 0: + frame1.remove(newtCanvasAWT); + frame2.add(newtCanvasAWT, BorderLayout.CENTER); + frame2.pack(); + break; + case 1: + frame2.remove(newtCanvasAWT); + frame1.add(newtCanvasAWT, BorderLayout.CENTER); + frame1.pack(); + break; } + state++; } - glWindow.destroy(); - if(useLayout) { - frame.remove(overlayedAWTComponent); - } - frame.dispose(); + + frame1.dispose(); + frame2.dispose(); + glWindow1.destroy(true); } public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getInnerWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); @@ -193,8 +364,22 @@ public class TestParenting01AWT { } } + static int atoi(String a) { + int i=0; + try { + durationPerTest = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + public static void main(String args[]) throws IOException { - durationPerTest = 5000; + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } else if(args[i].equals("-wait")) { + waitReparent = atoi(args[++i]); + } + } String tstname = TestParenting01AWT.class.getName(); org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { tstname, diff --git a/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java index ee135e83e..37de52139 100755 --- a/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java +++ b/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java @@ -48,6 +48,7 @@ import javax.media.opengl.*; import javax.media.nativewindow.*; import javax.media.nativewindow.*; +import com.jogamp.opengl.util.Animator; import com.jogamp.newt.*; import com.jogamp.newt.event.*; import com.jogamp.newt.opengl.*; @@ -61,136 +62,202 @@ import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; public class TestParenting01NEWT { static int width, height; static long durationPerTest = 500; + static long waitReparent = 0; + static GLCapabilities glCaps; @BeforeClass public static void initClass() { width = 640; height = 480; + glCaps = new GLCapabilities(null); } - static Window createWindow(Screen screen, Capabilities caps) { - Assert.assertNotNull(caps); - Window window = NewtFactory.createWindow(screen, caps, false) ; - Assert.assertNotNull(window); - return window; - } + @Test + public void testWindowParenting01CreateVisibleDestroy() throws InterruptedException { + int x = 0; + int y = 0; - static Window createWindow(NativeWindow parent, Capabilities caps) { - Assert.assertNotNull(caps); - Window window = NewtFactory.createWindow(parent, caps, true); - Assert.assertNotNull(window); - return window; - } + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); - static void destroyWindow(Display display, Screen screen, Window window, GLWindow glWindow) { - if(null!=glWindow) { - glWindow.destroy(); - } - if(null!=window) { - window.destroy(); - } - if(null!=screen) { - screen.destroy(); - } - if(null!=display) { - display.destroy(); + GLWindow glWindow1 = GLWindow.create(glCaps); + Assert.assertNotNull(glWindow1); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeWindowValid()); + Assert.assertNull(glWindow1.getParentNativeWindow()); + glWindow1.setTitle("testWindowParenting01CreateVisibleDestroy"); + glWindow1.setSize(640, 480); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + + GLWindow glWindow2 = GLWindow.create(glWindow1, glCaps); + Assert.assertNotNull(glWindow2); + Assert.assertEquals(false, glWindow2.isVisible()); + Assert.assertEquals(false, glWindow2.isNativeWindowValid()); + Assert.assertEquals(glWindow1,glWindow2.getParentNativeWindow()); + glWindow2.setSize(320, 240); + GLEventListener demo2 = new Gears(); + setDemoFields(demo2, glWindow2, false); + glWindow2.addGLEventListener(demo2); + + // visible test + glWindow1.setVisible(true); + Assert.assertEquals(true, glWindow1.isVisible()); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + glWindow1.setVisible(false); + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertEquals(false, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + glWindow1.setVisible(true); + Assert.assertEquals(true, glWindow1.isVisible()); + Assert.assertEquals(true, glWindow1.isNativeWindowValid()); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + + Animator animator1 = new Animator(glWindow1); + animator1.start(); + Animator animator2 = new Animator(glWindow2); + animator2.start(); + while(animator1.isAnimating() && animator1.getDuration()<durationPerTest) { + Thread.sleep(100); } + animator1.stop(); + Assert.assertEquals(false, animator1.isAnimating()); + animator2.stop(); + Assert.assertEquals(false, animator2.isAnimating()); + + glWindow1.destroy(); // false + + Assert.assertEquals(false, glWindow1.isVisible()); + Assert.assertEquals(false, glWindow1.isNativeWindowValid()); + Assert.assertEquals(false, glWindow1.isDestroyed()); + + Assert.assertEquals(false, glWindow2.isVisible()); + Assert.assertEquals(false, glWindow2.isNativeWindowValid()); + Assert.assertEquals(false, glWindow2.isDestroyed()); + + glWindow1.destroy(true); + Assert.assertEquals(true, glWindow1.isDestroyed()); + Assert.assertEquals(true, glWindow2.isDestroyed()); + + // test double destroy .. + glWindow2.destroy(true); + Assert.assertEquals(true, glWindow2.isDestroyed()); } @Test - public void testWindowParenting01NewtOnNewtParentChildDraw() throws InterruptedException { - GLCapabilities caps = new GLCapabilities(null); - Assert.assertNotNull(caps); - Display display = NewtFactory.createDisplay(null); // local display - Assert.assertNotNull(display); - Screen screen = NewtFactory.createScreen(display, 0); // screen 0 - Assert.assertNotNull(screen); - - int x = 1; - int y = 1; + public void testWindowParenting02ReparentTop2Win() throws InterruptedException { + int x = 0; + int y = 0; NEWTEventFiFo eventFifo = new NEWTEventFiFo(); - Window window1 = createWindow(screen, caps); - Assert.assertNotNull(window1); - GLWindow glWindow1 = GLWindow.create(window1); - Assert.assertNotNull(glWindow1); - glWindow1.setSize(width, height); - Assert.assertEquals(width,glWindow1.getWidth()); - Assert.assertEquals(height,glWindow1.getHeight()); - glWindow1.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - PARENT"); - glWindow1.setPosition(x,y); - glWindow1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); - glWindow1.addWindowListener(new TraceWindowAdapter()); - glWindow1.setVisible(true); - Capabilities capsChosen = glWindow1.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); - Assert.assertNotNull(capsChosen); - Assert.assertTrue(capsChosen.isOnscreen()==true); + GLWindow glWindow1 = GLWindow.create(glCaps); + glWindow1.setTitle("testWindowParenting02ReparentTop2Win"); + glWindow1.setSize(640, 480); + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); - Window window2 = createWindow(window1, caps); - Assert.assertNotNull(window2); - GLWindow glWindow2 = GLWindow.create(window2); - Assert.assertNotNull(glWindow2); - glWindow2.setSize(width/2, height/2); - //Assert.assertEquals(width/2,glWindow2.getWidth()); - //Assert.assertEquals(height/2,glWindow2.getHeight()); - glWindow2.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - CHILD"); - glWindow2.setPosition(glWindow1.getWidth()/2, glWindow1.getHeight()/2); - glWindow2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); - glWindow2.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo))); - // glWindow2.addMouseListener(new TraceMouseAdapter()); + GLWindow glWindow2 = GLWindow.create(glCaps); + glWindow2.setSize(320, 240); + GLEventListener demo2 = new Gears(); + setDemoFields(demo2, glWindow2, false); + glWindow2.addGLEventListener(demo2); + + glWindow1.setVisible(true); glWindow2.setVisible(true); - capsChosen = glWindow2.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); - Assert.assertNotNull(capsChosen); - Assert.assertTrue(capsChosen.isOnscreen()==true); + Animator animator1 = new Animator(glWindow1); + animator1.start(); + Animator animator2 = new Animator(glWindow2); + animator2.start(); + + int state = 0; + while(animator1.isAnimating() && animator1.getDuration()<3*durationPerTest) { + Thread.sleep(durationPerTest); + switch(state) { + case 0: + glWindow2.reparentWindow(glWindow1, null); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + Assert.assertEquals(glWindow1,glWindow2.getParentNativeWindow()); + break; + case 1: + glWindow2.reparentWindow(null, null); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + Assert.assertNull(glWindow2.getParentNativeWindow()); + break; + } + state++; + } + animator1.stop(); + animator2.stop(); + + glWindow1.destroy(true); + glWindow2.destroy(true); + } + + @Test + public void testWindowParenting03ReparentWin2Top() throws InterruptedException { + int x = 0; + int y = 0; + + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); + + GLWindow glWindow1 = GLWindow.create(glCaps); + glWindow1.setTitle("testWindowParenting03ReparentWin2Top"); + glWindow1.setSize(640, 480); GLEventListener demo1 = new RedSquare(); - setDemoFields(demo1, window1, glWindow1, false); + setDemoFields(demo1, glWindow1, false); glWindow1.addGLEventListener(demo1); + GLWindow glWindow2 = GLWindow.create(glWindow1, glCaps); + glWindow2.setSize(320, 240); GLEventListener demo2 = new Gears(); - setDemoFields(demo2, window2, glWindow2, false); + setDemoFields(demo2, glWindow2, false); glWindow2.addGLEventListener(demo2); - boolean shouldQuit = false; - long duration = durationPerTest; - long step = 20; - NEWTEvent event; - - while (duration>0 && !shouldQuit) { - glWindow1.display(); - glWindow2.display(); - Thread.sleep(step); - duration -= step; - x += 1; - y += 1; - glWindow1.setPosition(x,y); - glWindow2.setPosition(glWindow1.getWidth()/2,glWindow1.getHeight()/2-y); - - while( null != ( event = (NEWTEvent) eventFifo.get() ) ) { - Window source = (Window) event.getSource(); - if(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY == event.getEventType()) { - shouldQuit = true; - } else if(event instanceof KeyEvent) { - KeyEvent keyEvent = (KeyEvent) event; - switch(keyEvent.getKeyChar()) { - case 'q': - shouldQuit = true; - break; - case 'f': - source.setFullscreen(!source.isFullscreen()); - break; - } - } + glWindow1.setVisible(true); + + Animator animator1 = new Animator(glWindow1); + animator1.start(); + Animator animator2 = new Animator(glWindow2); + animator2.start(); + + int state = 0; + while(animator1.isAnimating() && animator1.getDuration()<3*durationPerTest) { + Thread.sleep(durationPerTest); + switch(state) { + case 0: + glWindow2.reparentWindow(null, null); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + Assert.assertNull(glWindow2.getParentNativeWindow()); + break; + case 1: + glWindow2.reparentWindow(glWindow1, null); + Assert.assertEquals(true, glWindow2.isVisible()); + Assert.assertEquals(true, glWindow2.isNativeWindowValid()); + Assert.assertEquals(glWindow1,glWindow2.getParentNativeWindow()); + break; } + state++; } - destroyWindow(null, null, window2, glWindow2); - destroyWindow(display, screen, window1, glWindow1); + animator1.stop(); + animator2.stop(); + + glWindow1.destroy(true); } - public static void setDemoFields(GLEventListener demo, Window window, GLWindow glWindow, boolean debug) { + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); - Assert.assertNotNull(window); + Assert.assertNotNull(glWindow); + Window window = glWindow.getInnerWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); @@ -200,8 +267,22 @@ public class TestParenting01NEWT { } } + static int atoi(String a) { + int i=0; + try { + durationPerTest = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + public static void main(String args[]) throws IOException { - durationPerTest = 5000; + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } else if(args[i].equals("-wait")) { + waitReparent = atoi(args[++i]); + } + } String tstname = TestParenting01NEWT.class.getName(); org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { tstname, diff --git a/src/junit/com/jogamp/test/junit/newt/TestParenting02AWT.java b/src/junit/com/jogamp/test/junit/newt/TestParenting02AWT.java new file mode 100755 index 000000000..dc330c4a9 --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestParenting02AWT.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2010 Sven Gothel. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name Sven Gothel or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SVEN GOTHEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.test.junit.newt; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Test; + +import java.awt.Button; +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Frame; + +import javax.media.opengl.*; +import javax.media.nativewindow.*; + +import com.jogamp.opengl.util.Animator; +import com.jogamp.newt.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.opengl.*; +import com.jogamp.newt.awt.NewtCanvasAWT; + +import java.io.IOException; + +import com.jogamp.test.junit.util.*; +import com.jogamp.test.junit.jogl.demos.es1.RedSquare; +import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; + +public class TestParenting02AWT { + static int width, height; + static long durationPerTest = 300; + static long waitReparent = 300; + + @BeforeClass + public static void initClass() { + width = 640; + height = 480; + } + + @Test + public void testWindowParenting01NewtChildOnAWTParentLayouted() throws InterruptedException { + runNewtChildOnAWTParent(true, false); + } + + @Test + public void testWindowParenting02NewtChildOnAWTParentLayoutedDef() throws InterruptedException { + runNewtChildOnAWTParent(true, true); + } + + @Test + public void testWindowParenting03NewtChildOnAWTParentDirect() throws InterruptedException { + runNewtChildOnAWTParent(false, false); + } + + @Test + public void testWindowParenting04NewtChildOnAWTParentDirectDef() throws InterruptedException { + runNewtChildOnAWTParent(false, true); + } + + public void runNewtChildOnAWTParent(boolean useLayout, boolean deferredPeer) throws InterruptedException { + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); + + // setup NEWT GLWindow .. + GLWindow glWindow = GLWindow.create(new GLCapabilities(null)); + Assert.assertNotNull(glWindow); + glWindow.setTitle("NEWT - CHILD"); + glWindow.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + glWindow.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo))); + GLEventListener demo = new Gears(); + setDemoFields(demo, glWindow, false); + glWindow.addGLEventListener(demo); + + // attach NEWT GLWindow to AWT Canvas + NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow); + Assert.assertNotNull(newtCanvasAWT); + Assert.assertEquals(false, glWindow.isVisible()); + Assert.assertEquals(false, glWindow.isNativeWindowValid()); + Assert.assertNull(glWindow.getParentNativeWindow()); + + Frame frame = new Frame("AWT Parent Frame"); + Assert.assertNotNull(frame); + if(useLayout) { + frame.setLayout(new BorderLayout()); + frame.add(new Button("North"), BorderLayout.NORTH); + frame.add(new Button("South"), BorderLayout.SOUTH); + frame.add(new Button("East"), BorderLayout.EAST); + frame.add(new Button("West"), BorderLayout.WEST); + if(!deferredPeer) { + frame.add(newtCanvasAWT, BorderLayout.CENTER); + } + } else { + if(!deferredPeer) { + frame.add(newtCanvasAWT); + } + } + + frame.setSize(width, height); + + frame.setVisible(true); + // X11: true, Windows: false - Assert.assertEquals(true, glWindow.isVisible()); + + if(deferredPeer) { + if(useLayout) { + frame.add(newtCanvasAWT, BorderLayout.CENTER); + } else { + frame.add(newtCanvasAWT); + } + } + + // Since it is not defined when AWT's addNotify call happen + // we just have to wait for it in this junit test + // because we have assertions on the state. + // Regular application shall not need to do that. + do { + Thread.yield(); + // 1st display .. creation + glWindow.display(); + } while(!glWindow.isNativeWindowValid()) ; + + Assert.assertEquals(true, glWindow.isNativeWindowValid()); + Assert.assertNotNull(glWindow.getParentNativeWindow()); + System.out.println("+++++++++++++++++++ 1st ADDED"); + Thread.sleep(waitReparent); + + if(useLayout) { + // test some fancy re-layout .. + frame.remove(newtCanvasAWT); + Assert.assertEquals(false, glWindow.isVisible()); + Assert.assertEquals(true, glWindow.isNativeWindowValid()); + Assert.assertNull(glWindow.getParentNativeWindow()); + System.out.println("+++++++++++++++++++ REMOVED!"); + Thread.sleep(waitReparent); + + // should recreate properly .. + frame.add(newtCanvasAWT, BorderLayout.CENTER); + glWindow.display(); + Assert.assertEquals(true, glWindow.isVisible()); + Assert.assertEquals(true, glWindow.isNativeWindowValid()); + Assert.assertNotNull(glWindow.getParentNativeWindow()); + System.out.println("+++++++++++++++++++ 2nd ADDED"); + Thread.sleep(waitReparent); + } + + long duration = durationPerTest; + long step = 20; + NEWTEvent event; + boolean shouldQuit = false; + + while (duration>0 && !shouldQuit) { + glWindow.display(); + Thread.sleep(step); + duration -= step; + + while( null != ( event = (NEWTEvent) eventFifo.get() ) ) { + Window source = (Window) event.getSource(); + if(event instanceof KeyEvent) { + KeyEvent keyEvent = (KeyEvent) event; + switch(keyEvent.getKeyChar()) { + case 'q': + shouldQuit = true; + break; + case 'f': + source.setFullscreen(!source.isFullscreen()); + break; + } + } + } + } + System.out.println("+++++++++++++++++++ END"); + Thread.sleep(waitReparent); + + glWindow.destroy(); + if(useLayout) { + frame.remove(newtCanvasAWT); + } + frame.dispose(); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getInnerWindow(); + 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 { + durationPerTest = 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("-wait")) { + waitReparent = atoi(args[++i]); + } + } + String tstname = TestParenting02AWT.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" } ); + } + +} diff --git a/src/junit/com/jogamp/test/junit/newt/TestParenting02NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestParenting02NEWT.java new file mode 100755 index 000000000..0fa0bef0f --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestParenting02NEWT.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2010 Sven Gothel. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name Sven Gothel or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SVEN GOTHEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.test.junit.newt; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Test; + +import javax.media.opengl.*; +import javax.media.nativewindow.*; +import javax.media.nativewindow.*; + +import com.jogamp.newt.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.opengl.*; + +import java.io.IOException; + +import com.jogamp.test.junit.util.*; +import com.jogamp.test.junit.jogl.demos.es1.RedSquare; +import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; + +public class TestParenting02NEWT { + static int width, height; + static long durationPerTest = 500; + + @BeforeClass + public static void initClass() { + width = 640; + height = 480; + } + + static Window createWindow(Screen screen, Capabilities caps) { + Assert.assertNotNull(caps); + Window window = NewtFactory.createWindow(screen, caps, false) ; + Assert.assertNotNull(window); + return window; + } + + static Window createWindow(NativeWindow parent, Capabilities caps) { + Assert.assertNotNull(caps); + Window window = NewtFactory.createWindow(parent, caps, true); + Assert.assertNotNull(window); + return window; + } + + static void destroyWindow(Display display, Screen screen, Window window, GLWindow glWindow) { + if(null!=glWindow) { + glWindow.destroy(); + } + if(null!=window) { + window.destroy(); + } + if(null!=screen) { + screen.destroy(); + } + if(null!=display) { + display.destroy(); + } + } + + @Test + public void testWindowParenting01NewtOnNewtParentChildDraw() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(null); + Assert.assertNotNull(caps); + Display display = NewtFactory.createDisplay(null); // local display + Assert.assertNotNull(display); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + Assert.assertNotNull(screen); + + int x = 1; + int y = 1; + + NEWTEventFiFo eventFifo = new NEWTEventFiFo(); + + Window window1 = createWindow(screen, caps); + Assert.assertNotNull(window1); + GLWindow glWindow1 = GLWindow.create(window1); + Assert.assertNotNull(glWindow1); + glWindow1.setSize(width, height); + Assert.assertEquals(width,glWindow1.getWidth()); + Assert.assertEquals(height,glWindow1.getHeight()); + glWindow1.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - PARENT"); + glWindow1.setPosition(x,y); + glWindow1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + glWindow1.addWindowListener(new TraceWindowAdapter()); + glWindow1.setVisible(true); + Capabilities capsChosen = glWindow1.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + Assert.assertNotNull(capsChosen); + Assert.assertTrue(capsChosen.isOnscreen()==true); + + Window window2 = createWindow(window1, caps); + Assert.assertNotNull(window2); + GLWindow glWindow2 = GLWindow.create(window2); + Assert.assertNotNull(glWindow2); + glWindow2.setSize(width/2, height/2); + //Assert.assertEquals(width/2,glWindow2.getWidth()); + //Assert.assertEquals(height/2,glWindow2.getHeight()); + glWindow2.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - CHILD"); + glWindow2.setPosition(glWindow1.getWidth()/2, glWindow1.getHeight()/2); + glWindow2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + glWindow2.addWindowListener(new TraceWindowAdapter(new WindowAction(eventFifo))); + // glWindow2.addMouseListener(new TraceMouseAdapter()); + glWindow2.setVisible(true); + capsChosen = glWindow2.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + Assert.assertNotNull(capsChosen); + Assert.assertTrue(capsChosen.isOnscreen()==true); + + GLEventListener demo1 = new RedSquare(); + setDemoFields(demo1, window1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + + GLEventListener demo2 = new Gears(); + setDemoFields(demo2, window2, glWindow2, false); + glWindow2.addGLEventListener(demo2); + + boolean shouldQuit = false; + long duration = durationPerTest; + long step = 20; + NEWTEvent event; + + while (duration>0 && !shouldQuit) { + glWindow1.display(); + glWindow2.display(); + Thread.sleep(step); + duration -= step; + x += 1; + y += 1; + glWindow1.setPosition(x,y); + glWindow2.setPosition(glWindow1.getWidth()/2,glWindow1.getHeight()/2-y); + + while( null != ( event = (NEWTEvent) eventFifo.get() ) ) { + Window source = (Window) event.getSource(); + if(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY == event.getEventType()) { + shouldQuit = true; + } else if(event instanceof KeyEvent) { + KeyEvent keyEvent = (KeyEvent) event; + switch(keyEvent.getKeyChar()) { + case 'q': + shouldQuit = true; + break; + case 'f': + source.setFullscreen(!source.isFullscreen()); + break; + } + } + } + } + destroyWindow(null, null, window2, glWindow2); + destroyWindow(display, screen, window1, glWindow1); + } + + public static void setDemoFields(GLEventListener demo, Window window, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(window); + 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 { + durationPerTest = 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 = TestParenting02NEWT.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" } ); + } + +} diff --git a/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java index e0affa4ab..58ea235df 100755 --- a/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java +++ b/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java @@ -69,9 +69,11 @@ public class TestWindows01NEWT { Window window = NewtFactory.createWindow(screen, caps, onscreen && undecorated); Assert.assertNotNull(window); window.setSize(width, height); + Assert.assertEquals(false,window.isNativeWindowValid()); Assert.assertEquals(false,window.isVisible()); window.setVisible(true); Assert.assertEquals(true,window.isVisible()); + Assert.assertEquals(true,window.isNativeWindowValid()); // Assert.assertEquals(width,window.getWidth()); // Assert.assertEquals(height,window.getHeight()); // System.out.println("Created: "+window); @@ -103,6 +105,27 @@ public class TestWindows01NEWT { } @Test + public void testWindowNativeRecreate01Simple() throws InterruptedException { + Capabilities caps = new Capabilities(); + Assert.assertNotNull(caps); + Display display = NewtFactory.createDisplay(null); // local display + Assert.assertNotNull(display); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + Assert.assertNotNull(screen); + + Window window = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); + window.destroy(); + Assert.assertEquals(false,window.isNativeWindowValid()); + Assert.assertEquals(false,window.isVisible()); + + window.setVisible(true); + Assert.assertEquals(true,window.isNativeWindowValid()); + + Thread.sleep(100); // 100 ms + destroyWindow(display, screen, window); + } + + @Test public void testWindowDecor01Simple() throws InterruptedException { Capabilities caps = new Capabilities(); Assert.assertNotNull(caps); @@ -112,7 +135,7 @@ public class TestWindows01NEWT { Assert.assertNotNull(screen); Window window = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); - Thread.sleep(1000); // 1000 ms + Thread.sleep(100); // 100 ms destroyWindow(display, screen, window); } @@ -126,7 +149,7 @@ public class TestWindows01NEWT { Assert.assertNotNull(screen); Window window = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); - Thread.sleep(1000); // 1000 ms + Thread.sleep(100); // 100 ms destroyWindow(null, null, window); destroyWindow(display, screen, window); } @@ -142,7 +165,7 @@ public class TestWindows01NEWT { Window window1 = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); Window window2 = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); - Thread.sleep(1000); // 1000 ms + Thread.sleep(100); // 100 ms destroyWindow(null, null, window2); destroyWindow(display, screen, window1); } diff --git a/src/junit/com/jogamp/test/junit/newt/WindowAction.java b/src/junit/com/jogamp/test/junit/newt/WindowAction.java index fa50cb34a..c52b895e6 100644 --- a/src/junit/com/jogamp/test/junit/newt/WindowAction.java +++ b/src/junit/com/jogamp/test/junit/newt/WindowAction.java @@ -32,7 +32,6 @@ package com.jogamp.test.junit.newt; -import com.jogamp.opengl.util.Animator; import com.jogamp.newt.event.*; class WindowAction extends WindowAdapter { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullWindow.java index 4458d7b3d..a1c2b594c 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/NullWindow.java @@ -117,10 +117,6 @@ public class NullWindow implements NativeWindow, SurfaceChangeable { return config; } - public Object getWrappedWindow() { - return null; - } - public final boolean isTerminalObject() { return true; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java index 06ce54368..52c211615 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/RecursiveToolkitLock.java @@ -6,8 +6,8 @@ import javax.media.nativewindow.*; // Reentrance locking toolkit // public class RecursiveToolkitLock implements ToolkitLock { - private Thread owner; - private int recursionCount; + private Thread owner = null; + private int recursionCount = 0; private Exception lockedStack = null; private static final long timeout = 3000; // maximum wait 3s @@ -31,6 +31,10 @@ public class RecursiveToolkitLock implements ToolkitLock { return null != owner; } + public synchronized int getRecursionCount() { + return recursionCount; + } + /** Recursive and blocking lockSurface() implementation */ public synchronized void lock() { Thread cur = Thread.currentThread(); @@ -49,10 +53,10 @@ public class RecursiveToolkitLock implements ToolkitLock { } if(owner != null) { lockedStack.printStackTrace(); - throw new RuntimeException("Waited "+timeout+"ms for: "+owner+" - "+cur); + throw new RuntimeException("Waited "+timeout+"ms for: "+owner+" - "+cur+", with recursionCount "+recursionCount+", lock: "+this); } owner = cur; - lockedStack = new Exception("Previously locked by "+owner); + lockedStack = new Exception("Previously locked by "+owner+", lock: "+this); } @@ -62,7 +66,7 @@ public class RecursiveToolkitLock implements ToolkitLock { } /** Recursive and unblocking unlockSurface() implementation */ - public synchronized void unlock(Runnable releaseAfterUnlockBeforeNotify) { + public synchronized void unlock(Runnable taskAfterUnlockBeforeNotify) { Thread cur = Thread.currentThread(); if (owner != cur) { lockedStack.printStackTrace(); @@ -74,8 +78,8 @@ public class RecursiveToolkitLock implements ToolkitLock { } owner = null; lockedStack = null; - if(null!=releaseAfterUnlockBeforeNotify) { - releaseAfterUnlockBeforeNotify.run(); + if(null!=taskAfterUnlockBeforeNotify) { + taskAfterUnlockBeforeNotify.run(); } notifyAll(); } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java index 08b2ceec9..6e3c62d3b 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java @@ -59,16 +59,7 @@ public class X11Util { static { NWJNILibLoader.loadNativeWindow("x11"); - // No concurrent threading support in case AWT could be used, - // Mixing AWT and X11/NEWT results in a segmentation fault: - // C pthread_mutex_lock+0x4 - // J sun.awt.X11.XlibWrapper.XGetDefault - // J sun.awt.X11.XToolkit.initializeMultiClickTime - // J sun.awt.X11.XToolkit.getMultiClickTime - // - // It seems like (Oracle's) AWT's Display locking is buggy. - // - initialize( ! NativeWindowFactory.isAWTAvailable() ) ; + initialize( true ); long dpy = X11Lib.XOpenDisplay(null); XLockDisplay(dpy); diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index 37606e8d8..09c605e1c 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -65,9 +65,8 @@ public interface NativeWindow extends SurfaceUpdatedListener { /** * Lock the surface of this native window<P> * - * The window handle, see {@link #getWindowHandle()}, - * and the surface handle, see {@link #lockSurface()}, <br> - * shall be set and be valid after a successfull call, + * The surface handle, see {@link #lockSurface()}, <br> + * shall be set and valid after a successfull call, * ie a return value other than {@link #LOCK_SURFACE_NOT_READY}.<P> * * The semantics of the underlying native locked resource @@ -88,8 +87,7 @@ public interface NativeWindow extends SurfaceUpdatedListener { /** * Unlock the surface of this native window * - * Shall not modify the window handle, see {@link #getWindowHandle()}, - * or the surface handle, see {@link #lockSurface()} <P> + * Shall not modify the surface handle, see {@link #lockSurface()} <P> * * @throws NativeWindowException if surface is not locked * @@ -140,11 +138,6 @@ public interface NativeWindow extends SurfaceUpdatedListener { /** * Returns the window handle for this NativeWindow. <P> * - * The window handle should be set/update by {@link #lockSurface()}, - * where {@link #unlockSurface()} is not allowed to modify it.<br> - * After {@link #unlockSurface()} it is no more guaranteed - * that the window handle is still valid.<p> - * * The window handle shall reflect the platform one * for all window related operations, e.g. open, close, resize. <P> * diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 674a45ded..113ec547e 100755 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -146,7 +146,7 @@ public abstract class Display { final Display f_dpy = display; Thread current = Thread.currentThread(); display.edtUtil = new EDTUtil(current.getThreadGroup(), - "Display_"+display.getFQName()+"-"+current.getName(), + "Display_"+display.getFQName(), new Runnable() { public void run() { if(null!=f_dpy.getGraphicsDevice()) { @@ -253,7 +253,7 @@ public abstract class Display { public static final String getFQName(String type, String name) { if(null==type) type=nilString; if(null==name) name=nilString; - return type+":"+name; + return type+"_"+name; } public long getHandle() { @@ -277,7 +277,7 @@ public abstract class Display { } public String toString() { - return "NEWT-Display["+getFQName()+", refCount "+refCount+", "+aDevice+"]"; + return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", "+aDevice+"]"; } protected abstract void dispatchMessagesNative(); diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index 7860197ef..3959c6a8d 100755 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -106,101 +106,80 @@ public abstract class NewtFactory { * Create a top level Window entity, incl native creation */ public static Window createWindow(Screen screen, Capabilities caps) { - return Window.create(NativeWindowFactory.getNativeWindowType(true), null, 0, screen, caps, false); + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps, false); } /** * Create a top level Window entity, incl native creation */ public static Window createWindow(Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(NativeWindowFactory.getNativeWindowType(true), null, 0, screen, caps, undecorated); + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps, undecorated); } /** * Create a child Window entity attached to the given parent, incl native creation.<br> - * The Screen and Display information is regenrated utilizing the parents information.<br> + * The Screen and Display information is regenerated utilizing the parents information.<br> * <p> - * In case <code>parentWindowObject</code> is a {@link javax.media.nativewindow.NativeWindow},<br> - * we create a child {@link com.jogamp.newt.Window}, - * utilizing {@link com.jogamp.newt.NewtFactory#createWindowImpl(java.lang.String, javax.media.nativewindow.NativeWindow, com.jogamp.newt.Screen, javax.media.nativewindow.Capabilities, boolean)}<br></p>. - * <p> - * In case <code>parentWindowObject</code> is even a {@link com.jogamp.newt.Window}, the following applies:<br> - * {@link com.jogamp.newt.event.WindowEvent#EVENT_WINDOW_RESIZED} is not propagated to the child window for e.g. layout<br>, + * In case <code>parentWindowObject</code> is a {@link com.jogamp.newt.Window} instance,<br> + * the new window is added to it's list of children.<br> + * This assures proper handling of visibility, creation and destruction.<br> + * {@link com.jogamp.newt.event.WindowEvent#EVENT_WINDOW_RESIZED} is not propagated to the child window for layout<br>, * you have to add an appropriate {@link com.jogamp.newt.event.WindowListener} for this use case.<br> - * However, {@link com.jogamp.newt.event.WindowEvent#EVENT_WINDOW_DESTROY_NOTIFY} is propagated to the child window, so it will be closed properly.<br> * The parents visibility is passed to the new Window<br></p> * <p> * In case <code>parentWindowObject</code> is a different {@link javax.media.nativewindow.NativeWindow} implementation,<br> * you have to handle all events appropriatly.<br></p> * <p> - * In case <code>parentWindowObject</code> is a {@link java.awt.Component},<br> - * we utilize the {@link com.jogamp.newt.impl.awt.AWTNewtFactory#createNativeChildWindow(Object, com.jogamp.newt.Capabilities, boolean)} - * factory method.<br> - * The factory adds a {@link com.jogamp.newt.event.WindowListener} to propagate {@link com.jogamp.newt.event.WindowEvent}'s so - * your NEWT Window integrates into the AWT layout.<br> - * The parents visibility is passed to the new Window<br></p> * - * @param parentWindowObject either a NativeWindow or java.awt.Component + * @param parentWindowObject either a NativeWindow instance * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always - * - * @see com.jogamp.newt.NewtFactory#createWindow(long, com.jogamp.newt.Screen, javax.media.nativewindow.Capabilities, boolean) - * @see com.jogamp.newt.impl.awt.AWTNewtFactory#createNativeChildWindow(java.lang.Object, javax.media.nativewindow.Capabilities, boolean) */ - public static Window createWindow(Object parentWindowObject, Capabilities caps, boolean undecorated) { + public static Window createWindow(NativeWindow nParentWindow, Capabilities caps, boolean undecorated) { final String type = NativeWindowFactory.getNativeWindowType(true); - if(null==parentWindowObject) { - return createWindowImpl(type, null, null, caps, undecorated); + if(null==nParentWindow) { + return createWindowImpl(type, caps, undecorated); } - if(parentWindowObject instanceof NativeWindow) { - NativeWindow nParentWindow = (NativeWindow) parentWindowObject; - - Display display=null; - Screen screen=null; - Window parentWindow=null; - - if ( nParentWindow instanceof Window ) { - parentWindow = (Window) nParentWindow ; - Screen nParentScreen = parentWindow.getScreen(); - Display nParentDisplay = nParentScreen.getDisplay(); - display = NewtFactory.wrapDisplay(type, nParentDisplay.getHandle()); - screen = NewtFactory.createScreen(type, display, nParentScreen.getIndex()); - } else { - AbstractGraphicsConfiguration nParentConfig = nParentWindow.getGraphicsConfiguration(); - AbstractGraphicsScreen nParentScreen = nParentConfig.getScreen(); - AbstractGraphicsDevice nParentDevice = nParentScreen.getDevice(); - display = NewtFactory.wrapDisplay(type, nParentDevice.getHandle()); - screen = NewtFactory.createScreen(type, display, nParentScreen.getIndex()); - } - final Window win = createWindowImpl(type, nParentWindow, screen, caps, undecorated); - win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); - if ( null != parentWindow ) { - parentWindow.addWindowListener(new WindowAdapter() { - public void windowDestroyNotify(WindowEvent e) { - win.sendEvent(e); - } - }); - win.setVisible(parentWindow.isVisible()); - } - return win; + Screen screen = null; + AbstractGraphicsConfiguration nParentConfig = nParentWindow.getGraphicsConfiguration(); + if(null!=nParentConfig) { + AbstractGraphicsScreen nParentScreen = nParentConfig.getScreen(); + AbstractGraphicsDevice nParentDevice = nParentScreen.getDevice(); + Display display = NewtFactory.wrapDisplay(type, nParentDevice.getHandle()); + screen = NewtFactory.createScreen(type, display, nParentScreen.getIndex()); } else { - if(ReflectionUtil.instanceOf(parentWindowObject, "java.awt.Component")) { - if(ReflectionUtil.isClassAvailable("com.jogamp.newt.impl.awt.AWTNewtFactory")) { - return (Window) ReflectionUtil.callStaticMethod( - "com.jogamp.newt.impl.awt.AWTNewtFactory", - "createNativeChildWindow", - new Class[] { Object.class, Capabilities.class, java.lang.Boolean.TYPE}, - new Object[] { parentWindowObject, caps, new Boolean(undecorated) } ); - } - } + Display display = NewtFactory.createDisplay(type, null); // local display + screen = NewtFactory.createScreen(type, display, 0); // screen 0 + } + final Window win = createWindowImpl(type, nParentWindow, screen, caps, undecorated); + + win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); + if ( nParentWindow instanceof Window ) { + Window parentWindow = (Window) nParentWindow ; + parentWindow.getInnerWindow().addChild(win); + win.setVisible(parentWindow.isVisible()); } - throw new RuntimeException("No NEWT child Window factory method for parent object: "+parentWindowObject); + return win; } protected static Window createWindowImpl(String type, NativeWindow parentNativeWindow, Screen screen, Capabilities caps, boolean undecorated) { return Window.create(type, parentNativeWindow, 0, screen, caps, undecorated); } + protected static Window createWindowImpl(String type, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { + return Window.create(type, null, parentWindowHandle, screen, caps, undecorated); + } + + protected static Window createWindowImpl(String type, Screen screen, Capabilities caps, boolean undecorated) { + return Window.create(type, null, 0, screen, caps, undecorated); + } + + protected static Window createWindowImpl(String type, Capabilities caps, boolean undecorated) { + Display display = NewtFactory.createDisplay(type, null); // local display + Screen screen = NewtFactory.createScreen(type, display, 0); // screen 0 + return Window.create(type, null, 0, screen, caps, undecorated); + } + /** * Create a child Window entity attached to the given parent, incl native creation<br> * @@ -208,7 +187,7 @@ public abstract class NewtFactory { * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ public static Window createWindow(long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(NativeWindowFactory.getNativeWindowType(true), null, parentWindowHandle, screen, caps, undecorated); + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), parentWindowHandle, screen, caps, undecorated); } /** @@ -228,7 +207,7 @@ public abstract class NewtFactory { * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ public static Window createWindow(String type, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, null, 0, screen, caps, undecorated); + return createWindowImpl(type, null, screen, caps, undecorated); } public static Window createWindow(String type, Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { diff --git a/src/newt/classes/com/jogamp/newt/OffscreenWindow.java b/src/newt/classes/com/jogamp/newt/OffscreenWindow.java index 5b957afa5..0f75fbfa9 100644 --- a/src/newt/classes/com/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/com/jogamp/newt/OffscreenWindow.java @@ -71,7 +71,7 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { surfaceHandle = 0; } - public synchronized void destroy() { + public synchronized void destroy(boolean deep) { surfaceHandle = 0; } @@ -83,7 +83,7 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { return surfaceHandle; } - protected void setVisibleImpl() { + protected void setVisibleImpl(boolean visible) { } public void setSize(int width, int height) { @@ -92,14 +92,24 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { this.height = height; } } + protected void setSizeImpl(int width, int height) { + shouldNotCallThis(); + } public void setPosition(int x, int y) { // nop } + protected void setPositionImpl(int x, int y) { + shouldNotCallThis(); + } public boolean setFullscreen(boolean fullscreen) { // nop return false; } + protected boolean setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + shouldNotCallThis(); + return false; + } } diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 978b7f068..bb3fa8982 100755 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -90,10 +90,6 @@ public abstract class Window implements NativeWindow protected static Window create(String type, NativeWindow parentNativeWindow, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { try { - if(null==screen) { - Display display = NewtFactory.createDisplay(type, null); // local display - screen = NewtFactory.createScreen(type, display, 0); // screen 0 - } Class windowClass; if(caps.isOnscreen()) { windowClass = getWindowClass(type); @@ -101,7 +97,7 @@ public abstract class Window implements NativeWindow windowClass = OffscreenWindow.class; } Window window = (Window) windowClass.newInstance(); - window.invalidate(); + window.invalidate(true); window.parentNativeWindow = parentNativeWindow; window.parentWindowHandle = parentWindowHandle; window.screen = screen; @@ -126,7 +122,7 @@ public abstract class Window implements NativeWindow throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments)); } Window window = (Window) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; - window.invalidate(); + window.invalidate(true); window.screen = screen; window.caps = (Capabilities)caps.clone(); window.setUndecorated(undecorated); @@ -146,7 +142,7 @@ public abstract class Window implements NativeWindow protected Screen screen; - private NativeWindow parentNativeWindow; + protected NativeWindow parentNativeWindow; protected long parentWindowHandle; protected Capabilities caps; @@ -154,52 +150,81 @@ public abstract class Window implements NativeWindow protected long windowHandle; protected boolean fullscreen, visible; protected int width, height, x, y; - protected int eventMask; + + // non fullscreen dimensions .. + protected int nfs_width, nfs_height, nfs_x, nfs_y; protected String title = "Newt Window"; protected boolean undecorated = false; - private synchronized boolean createNative() { + private boolean createNative() { if( null==screen || 0!=windowHandle || !visible ) { - // NOP .. or already done return 0 != windowHandle ; } EDTUtil edtUtil = screen.getDisplay().getEDTUtil(); - if( null != edtUtil && !edtUtil.isCurrentThreadEDT() ) { + if( null != edtUtil && edtUtil.isRunning() && !edtUtil.isCurrentThreadEDT() ) { throw new NativeWindowException("EDT enabled but not on EDT"); } - if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.createNative() START ("+Thread.currentThread()+", "+this+")"); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() START ("+Thread.currentThread()+", "+this+")"); } if(validateParentWindowHandle()) { createNativeImpl(); - setVisibleImpl(); + setVisibleImpl(true); } - if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.createNative() END ("+Thread.currentThread()+", "+this+")"); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() END ("+Thread.currentThread()+", "+this+")"); } return 0 != windowHandle ; } private boolean validateParentWindowHandle() { - boolean ok = true; if(null!=parentNativeWindow) { + parentWindowHandle = getNativeWindowHandle(parentNativeWindow); + return 0 != parentWindowHandle ; + } + return true; + } + + private static long getNativeWindowHandle(NativeWindow nativeWindow) { + long handle = 0; + if(null!=nativeWindow) { + boolean ok = true; try { - parentNativeWindow.lockSurface(); + nativeWindow.lockSurface(); } catch (NativeWindowException nwe) { // parent native window not ready .. just skip action for now ok = false; + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: not successful yet: "+nwe); + } } if(ok) { - parentWindowHandle = parentNativeWindow.getWindowHandle(); - parentNativeWindow.unlockSurface(); - if(0==parentWindowHandle) { - throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+parentNativeWindow); + handle = nativeWindow.getWindowHandle(); + nativeWindow.unlockSurface(); + if(0==handle) { + throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+nativeWindow); + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: "+nativeWindow); } } } - return ok; + return handle; + } + + public void runOnEDTIfAvail(boolean wait, final Runnable task) { + Screen screen = getInnerWindow().getScreen(); + if(null==screen) { + throw new RuntimeException("Null screen of inner class: "+this); + } + EDTUtil edtUtil = screen.getDisplay().getEDTUtil(); + if(null!=edtUtil) { + edtUtil.invoke(wait, task); + } else { + task.run(); + } } /** @@ -209,6 +234,14 @@ public abstract class Window implements NativeWindow protected abstract void closeNative(); + public Capabilities getRequestedCapabilities() { + return (Capabilities)caps.clone(); + } + + public NativeWindow getParentNativeWindow() { + return parentNativeWindow; + } + public Screen getScreen() { return screen; } @@ -218,6 +251,8 @@ public abstract class Window implements NativeWindow sb.append(getClass().getName()+"[Config "+config+ "\n, "+screen+ + "\n, ParentWindow "+parentNativeWindow+ + "\n, ParentWindowHandle "+toHexString(parentWindowHandle)+ "\n, WindowHandle "+toHexString(getWindowHandle())+ "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ "\n, Pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ @@ -261,8 +296,12 @@ public abstract class Window implements NativeWindow undecorated = value; } + public boolean isUndecorated(boolean fullscreen) { + return 0 != parentWindowHandle || undecorated || fullscreen ; + } + public boolean isUndecorated() { - return undecorated; + return 0 != parentWindowHandle || undecorated || fullscreen ; } public void requestFocus() { @@ -273,16 +312,19 @@ public abstract class Window implements NativeWindow // /** Recursive and blocking lockSurface() implementation */ - public synchronized int lockSurface() { + public int lockSurface() { // We leave the ToolkitLock lock to the specializtion's discretion, // ie the implicit JAWTWindow in case of AWTWindow + if(isDestroyed() || !isNativeWindowValid()) { + return LOCK_SURFACE_NOT_READY; + } surfaceLock.lock(); screen.getDisplay().lockDisplay(); return LOCK_SUCCESS; } /** Recursive and unblocking unlockSurface() implementation */ - public synchronized void unlockSurface() throws NativeWindowException { + public void unlockSurface() throws NativeWindowException { surfaceLock.unlock( new Runnable() { public void run() { screen.getDisplay().unlockDisplay(); @@ -292,59 +334,84 @@ public abstract class Window implements NativeWindow // ie the implicit JAWTWindow in case of AWTWindow } - public synchronized boolean isSurfaceLocked() { + public boolean isSurfaceLocked() { return surfaceLock.isLocked(); } - public synchronized Thread getSurfaceLockOwner() { + public Thread getSurfaceLockOwner() { return surfaceLock.getOwner(); } - public synchronized Exception getLockedStack() { + public Exception getLockedStack() { return surfaceLock.getLockedStack(); } - public void destroy() { + /** + * <p> + * destroys the window and children and releases + * windowing related resources.<br></p> + * <p> + * all other resources and states are kept intact, + * ie listeners, parent handles and size, position etc.<br></p> + * + * @see #destroy(boolean) + * @see #invalidate() + */ + public final void destroy() { destroy(false); } - /** @param deep If true, the linked Screen and Display will be destroyed as well. */ - public void destroy(boolean deep) { - if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.destroy() start (deep "+deep+" - "+Thread.currentThread()+", "+this+")"); - } - synchronized(surfaceUpdatedListeners) { - surfaceUpdatedListeners = new ArrayList(); - } - synchronized(windowListeners) { - windowListeners = new ArrayList(); + class DestroyAction implements Runnable { + boolean deep; + public DestroyAction(boolean deep) { + this.deep = deep; } - synchronized(mouseListeners) { - mouseListeners = new ArrayList(); - } - synchronized(keyListeners) { - keyListeners = new ArrayList(); - } - synchronized(this) { - destructionLock.lock(); + public void run() { + windowLock(); try { + if(DEBUG_WINDOW_EVENT) { + System.err.println("Window.destroy(deep: "+deep+") START "+Thread.currentThread()+", "+this); + } + + // Childs first .. + ArrayList listeners = null; + synchronized(childWindows) { + listeners = childWindows; + } + for(Iterator i = listeners.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof Window) { + ((Window)nw).destroy(deep); + } else { + nw.destroy(); + } + } + + // Now us .. + if(deep) { + synchronized(childWindows) { + childWindows = new ArrayList(); + } + synchronized(surfaceUpdatedListeners) { + surfaceUpdatedListeners = new ArrayList(); + } + synchronized(windowListeners) { + windowListeners = new ArrayList(); + } + synchronized(mouseListeners) { + mouseListeners = new ArrayList(); + } + synchronized(keyListeners) { + keyListeners = new ArrayList(); + } + } Display dpy = null; if( null != screen && 0 != windowHandle ) { Screen scr = screen; dpy = (null!=screen) ? screen.getDisplay() : null; - EDTUtil edtUtil = (null!=dpy) ? dpy.getEDTUtil() : null; - if(null!=edtUtil) { - final Window f_win = this; - edtUtil.invokeAndWait(new Runnable() { - public void run() { - f_win.closeNative(); - } - } ); - } else { - closeNative(); - } + closeNative(); } - invalidate(); + invalidate(deep); if(deep) { if(null!=screen) { screen.destroy(); @@ -353,34 +420,85 @@ public abstract class Window implements NativeWindow dpy.destroy(); } } + if(DEBUG_WINDOW_EVENT) { + System.err.println("Window.destroy(deep: "+deep+") END "+Thread.currentThread()+", "+this); + } } finally { - destructionLock.unlock(); + windowUnlock(); } } - if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.destroy() end "+Thread.currentThread()); + } + + /** + * @param deep If true, all resources, ie listeners, parent handles, size, position + * and the referenced NEWT screen and display, will be destroyed as well. Be aware that if you call + * this method with deep = true, you will not be able to regenerate the Window. + * @see #destroy() + * @see #invalidate(boolean) + */ + public void destroy(boolean deep) { + if(!isDestroyed()) { + runOnEDTIfAvail(true, new DestroyAction(deep)); } } + /** + * <p> + * render all native window information invalid, + * as if the native window was destroyed.<br></p> + * <p> + * all other resources and states are kept intact, + * ie listeners, parent handles and size, position etc.<br></p> + * + * @see #destroy() + * @see #destroy(boolean) + * @see #invalidate(boolean) + */ public void invalidate() { - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - Exception e = new Exception("!!! Window Invalidate "+Thread.currentThread()); - e.printStackTrace(); + invalidate(false); + } + + /** + * @param deep if false only the native window handle is invalidated, otherwise all + * states (references and properties) are reset. Be aware that if you call + * this method with deep = true, you will not be able to regenerate the Window. + * @see #invalidate() + * @see #destroy() + * @see #destroy(boolean) + */ + public void invalidate(boolean deep) { + windowLock(); + try{ + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + String msg = new String("!!! Window Invalidate(deep: "+deep+") "+Thread.currentThread()); + System.err.println(msg); + //Exception e = new Exception(msg); + //e.printStackTrace(); + } + windowHandle = 0; + visible=false; + fullscreen=false; + + if(deep) { + screen = null; + parentWindowHandle = 0; + parentNativeWindow = null; + caps = null; + + // Default position and dimension will be re-set immediately by user + width = 128; + height = 128; + x=0; + y=0; + } + } finally { + windowUnlock(); } - screen = null; - parentNativeWindow = null; - parentWindowHandle = 0; - caps = null; - windowHandle = 0; - fullscreen=false; - visible=false; - eventMask = 0; + } - // Default position and dimension will be re-set immediately by user - width = 128; - height = 128; - x=0; - y=0; + /** @return true if the native window handle is valid and ready to operate */ + public boolean isNativeWindowValid() { + return 0 != windowHandle ; } public boolean isDestroyed() { @@ -391,10 +509,6 @@ public abstract class Window implements NativeWindow return false; } - protected void clearEventMask() { - eventMask=0; - } - public long getDisplayHandle() { return screen.getDisplay().getHandle(); } @@ -442,6 +556,14 @@ public abstract class Window implements NativeWindow return new Insets(0,0,0,0); } + /** Returns the most inner Window instance.<br> + Currently only {@link com.jogamp.newt.opengl.GLWindow} + has an aggregation to an inner Window instance. + */ + public Window getInnerWindow() { + return this; + } + /** If this Window actually wraps one from another toolkit such as the AWT, this will return a non-null value. */ public Object getWrappedWindow() { @@ -468,7 +590,7 @@ public abstract class Window implements NativeWindow return fullscreen; } - private boolean autoDrawableMember = false; + private boolean handleDestroyNotify = true; /** If the implementation is capable of detecting a device change return true and clear the status/reason of the change. */ @@ -477,107 +599,258 @@ public abstract class Window implements NativeWindow } /** - * If set to true, - * certain action will be performed by the owning - * AutoDrawable, ie the destroy() call within windowDestroyNotify() + * If set to true, the default value, this NEWT Window implementation will + * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.<br> + * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify()}. */ - public void setAutoDrawableClient(boolean b) { - autoDrawableMember = b; + public void setHandleDestroyNotify(boolean b) { + handleDestroyNotify = b; } protected void windowDestroyNotify() { if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.windowDestroyNotify start "+Thread.currentThread()); + System.err.println("Window.windowDestroyNotify START "+Thread.currentThread()); } sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - if(!autoDrawableMember && !destructionLock.isLocked()) { + if(handleDestroyNotify && !isDestroyed()) { destroy(); } if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.windowDestroyeNotify end "+Thread.currentThread()); + System.err.println("Window.windowDestroyeNotify END "+Thread.currentThread()); } } protected void windowDestroyed() { if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.windowDestroyed "+Thread.currentThread()); + System.err.println("Window.windowDestroyed "+Thread.currentThread()); } - if(!destructionLock.isLocked()) { - invalidate(); + invalidate(); + } + + protected boolean reparentWindowImpl() { + // default implementation, no native reparenting support + return false; + } + + /** + * Change this window's parent window.<br> + * <P> + * In case the old parent is not null and a Window, + * this window is removed from it's list of children.<br> + * In case the new parent is not null and a Window, + * this window is added to it's list of children.<br></P> + * + * @param newParent the new parent NativeWindow. If null, this Window becomes a top level window. + * @param newScreen if not null and this window handle is not yet set + * this Screen is being used. + */ + public void reparentWindow(NativeWindow newParent, Screen newScreen) { + windowLock(); + try{ + if ( 0 == windowHandle && null != newScreen ) { + screen = newScreen; + } + long newParentHandle = 0 ; + if(null!=newParent) { + newParentHandle = getNativeWindowHandle(newParent); + if ( 0 == newParentHandle ) { + return; // bail out .. not ready yet + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("reparent: START ("+Thread.currentThread()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+", visible "+visible+", parentNativeWindow "+(null!=parentNativeWindow)); + } + + if(null!=parentNativeWindow && parentNativeWindow instanceof Window) { + ((Window)parentNativeWindow).getInnerWindow().removeChild(this); + } + parentNativeWindow = newParent; + if(parentNativeWindow instanceof Window) { + ((Window)parentNativeWindow).getInnerWindow().addChild(this); + } + + if(newParentHandle != parentWindowHandle) { + parentWindowHandle = newParentHandle; + if(0!=parentWindowHandle) { + // reset position to 0/0 within parent space + // FIXME .. cache position ? + x = 0; + y = 0; + } + if(!reparentWindowImpl()) { + parentWindowHandle = 0; + + // do it the hard way .. reconstruction with setVisible(true) + if( 0 != windowHandle ) { + destroy(false); + } + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("reparentWindow: END ("+Thread.currentThread()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentNativeWindow "+(null!=parentNativeWindow)); + } + } finally { + windowUnlock(); + } + } + + class VisibleAction implements Runnable { + boolean visible; + public VisibleAction(boolean visible) { + this.visible = visible; + } + public void run() { + windowLock(); + try{ + if( !isDestroyed() ) { + ArrayList listeners = null; + synchronized(childWindows) { + listeners = childWindows; + } + if(!visible && listeners.size()>0) { + for(Iterator i = listeners.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof Window) { + ((Window)nw).setVisible(false); + } + } + } + if(0==windowHandle && visible) { + Window.this.visible = visible; + if( 0<width*height ) { + createNative(); + } + } else if(Window.this.visible != visible) { + Window.this.visible = visible; + if(0 != windowHandle) { + setVisibleImpl(visible); + } + } + if(0!=windowHandle && visible && listeners.size()>0) { + for(Iterator i = listeners.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof Window) { + ((Window)nw).setVisible(true); + } + } + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setVisible: END ("+Thread.currentThread()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+Window.this.visible); + } + } finally { + windowUnlock(); + } } } /** * <p> - * <code>setVisible</code> makes the window visible if <code>visible</code> is true, - * otherwise the window becomes invisible.<br></p> + * <code>setVisible</code> makes the window and children visible if <code>visible</code> is true, + * otherwise the window and children becomes invisible.<br></p> * <p> * The <code>setVisible(true)</code> is responsible to actual create the native window.<br></p> * <p> + * Zero size semantics are respected, see {@link #setSize(int,int)}:<br> + * <pre> + * if ( 0 == windowHandle && visible ) { + * this.visible = visible; + * if( 0<width*height ) { + * createNative(); + * } + * } else if ( this.visible != visible ) { + * this.visible = visible; + * setNativeSizeImpl(); + * } + * </pre></p> + * <p> * In case this window is a child window and a parent {@link javax.media.nativewindow.NativeWindow} is being used,<br> * the parent's {@link javax.media.nativewindow.NativeWindow} handle is retrieved via {@link javax.media.nativewindow.NativeWindow#getWindowHandle()}.<br> * If this action fails, ie if the parent {@link javax.media.nativewindow.NativeWindow} is not valid yet,<br> * no native window is created yet and <code>setVisible(true)</code> shall be repeated when it is.<br></p> */ - public void setVisible(final boolean visible) { - setVisible(visible, false); - } - - public void setVisible(final boolean visible, boolean deferred) { - if(!isDestroyed()) { - EDTUtil edtUtil = screen.getDisplay().getEDTUtil(); - if(null!=edtUtil) { - edtUtil.invoke(deferred, new Runnable() { - public void run() { - setVisibleTask(visible); - } - }); - } else { - setVisibleTask(visible); - } - } - } - - private synchronized void setVisibleTask(final boolean visible) { + public void setVisible(boolean visible) { if(DEBUG_IMPLEMENTATION) { - System.err.println("setVisibleTask: START ("+Thread.currentThread()+") "+this.x+"/"+this.y+" "+this.width+"x"+this.height+", fs "+fullscreen+", windowHandle "+windowHandle+", visible: "+this.visible+" -> "+visible); - } - int didit = 0; - if(0==windowHandle && visible) { - this.visible = visible; - didit = 01; - if( createNative() ) { - didit = 11; - } - } else if(this.visible != visible) { - this.visible = visible; - didit = 2; - if(0 != windowHandle) { - setVisibleImpl(); - didit = 22; - } + String msg = new String("Window setVisible: START ("+Thread.currentThread()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentNativeWindow "+(null!=parentNativeWindow)); + //System.err.println(msg); + Exception ee = new Exception(msg); + ee.printStackTrace(); } - if(DEBUG_IMPLEMENTATION) { - System.err.println("setVisibleTask: END ("+Thread.currentThread()+") didit "+didit+", "+this.x+"/"+this.y+" "+this.width+"x"+this.height+", fs "+fullscreen+", windowHandle "+windowHandle+", visible: "+visible); + if(!isDestroyed()) { + runOnEDTIfAvail(true, new VisibleAction(visible)); } } - - protected abstract void setVisibleImpl(); + protected abstract void setVisibleImpl(boolean visible); /** * Sets the size of the client area of the window, excluding decorations * Total size of the window will be * {@code width+insets.left+insets.right, height+insets.top+insets.bottom}<br> - * - * This call is ignored if in fullscreen mode.<br> + * <p> + * Zero size semantics are respected, see {@link #setVisible(boolean)}:<br> + * <pre> + * if ( 0 != windowHandle && 0>=width*height && visible ) { + * setVisible(false); + * } else if ( 0 == windowHandle && 0<width*height && visible ) { + * setVisible(true); + * } else { + * // as expected .. + * } + * </pre></p> + * <p> + * This call is ignored if in fullscreen mode.<br></p> * * @param width of the client area of the window * @param height of the client area of the window */ - public abstract void setSize(int width, int height); + public void setSize(int width, int height) { + int visibleAction = 0; // 1 invisible, 2 visible + windowLock(); + try{ + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setSize: START "+this.width+"x"+this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible); + //System.err.println(msg); + Exception e = new Exception(msg); + e.printStackTrace(); + } + if (width != this.width || this.height != height) { + if(!fullscreen) { + nfs_width=width; + nfs_height=height; + if ( 0 != windowHandle && 0>=width*height && visible ) { + visibleAction=1; // invisible + this.width = 0; + this.height = 0; + } else if ( 0 == windowHandle && 0<width*height && visible ) { + visibleAction = 2; // visible + this.width = width; + this.height = height; + } else if ( 0 != windowHandle ) { + // this width/height will be set by windowChanged, called by X11 + setSizeImpl(width, height); + } else { + this.width = width; + this.height = height; + } + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: END "+this.width+"x"+this.height+", visibleAction "+visibleAction); + } + } finally { + windowUnlock(); + } + if(visibleAction>0) { + setVisible( ( 1 == visibleAction ) ? false : true ); + } + } + protected abstract void setSizeImpl(int width, int height); /** * Sets the location of the top left corner of the window, including @@ -589,13 +862,103 @@ public abstract class Window implements NativeWindow * @param x coord of the top left corner * @param y coord of the top left corner */ - public abstract void setPosition(int x, int y); + public void setPosition(int x, int y) { + windowLock(); + try{ + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)); + } + if ( this.x != x || this.y != y ) { + if(!fullscreen) { + nfs_x=x; + nfs_y=y; + if(0!=windowHandle) { + // this x/y will be set by windowChanged, called by X11 + setPositionImpl(x, y); + } else { + this.x = x; + this.y = y; + } + } + } + } finally { + windowUnlock(); + } + } + protected abstract void setPositionImpl(int x, int y); + + public boolean setFullscreen(boolean fullscreen) { + windowLock(); + try{ + if(0!=windowHandle && this.fullscreen!=fullscreen) { + int x,y,w,h; + if(fullscreen) { + x = 0; y = 0; + w = screen.getWidth(); + h = screen.getHeight(); + } else { + x = nfs_x; + y = nfs_y; + w = nfs_width; + h = nfs_height; + } + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()); + } + this.fullscreen = setFullscreenImpl(fullscreen, x, y, w, h); + } + return this.fullscreen; + } finally { + windowUnlock(); + } + } + protected abstract boolean setFullscreenImpl(boolean fullscreen, int x, int y, int widht, int height); - public abstract boolean setFullscreen(boolean fullscreen); + // + // Child Window Management + // + + private ArrayList childWindows = new ArrayList(); + + protected void removeChild(NativeWindow win) { + synchronized(childWindows) { + ArrayList newChildWindows = (ArrayList) childWindows.clone(); + newChildWindows.remove(win); + childWindows = newChildWindows; + } + } + + protected void addChild(NativeWindow win) { + if (win == null) { + return; + } + synchronized(childWindows) { + ArrayList newChildWindows = (ArrayList) childWindows.clone(); + newChildWindows.add(win); + childWindows = newChildWindows; + } + } + + // + // Generic Event Support + // + + public void sendEvent(NEWTEvent e) { + if(e instanceof WindowEvent) { + sendWindowEvent((WindowEvent)e); + } else if(e instanceof KeyEvent) { + sendKeyEvent((KeyEvent)e); + } else if(e instanceof MouseEvent) { + sendMouseEvent((MouseEvent)e); + } else if(e instanceof PaintEvent) { + sendPaintEvent((PaintEvent)e); + } + } // // SurfaceUpdatedListener Support // + private ArrayList surfaceUpdatedListeners = new ArrayList(); public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { @@ -643,22 +1006,6 @@ public abstract class Window implements NativeWindow } } - // - // Generic Event Support - // - - public void sendEvent(NEWTEvent e) { - if(e instanceof WindowEvent) { - sendWindowEvent((WindowEvent)e); - } else if(e instanceof KeyEvent) { - sendKeyEvent((KeyEvent)e); - } else if(e instanceof MouseEvent) { - sendMouseEvent((MouseEvent)e); - } else if(e instanceof PaintEvent) { - sendPaintEvent((PaintEvent)e); - } - } - // // MouseListener/Event Support // @@ -704,7 +1051,7 @@ public abstract class Window implements NativeWindow return; // .. invalid .. } if(DEBUG_MOUSE_EVENT) { - System.out.println("sendMouseEvent: "+MouseEvent.getEventTypeString(eventType)+ + System.err.println("sendMouseEvent: "+MouseEvent.getEventTypeString(eventType)+ ", mod "+modifiers+", pos "+x+"/"+y+", button "+button); } if(button<0||button>MouseEvent.BUTTON_NUMBER) { @@ -751,7 +1098,7 @@ public abstract class Window implements NativeWindow sendMouseEvent(e); if(null!=eClicked) { if(DEBUG_MOUSE_EVENT) { - System.out.println("sendMouseEvent: synthesized MOUSE_CLICKED event"); + System.err.println("sendMouseEvent: synthesized MOUSE_CLICKED event"); } sendMouseEvent(eClicked); } @@ -759,7 +1106,7 @@ public abstract class Window implements NativeWindow protected void sendMouseEvent(MouseEvent e) { if(DEBUG_MOUSE_EVENT) { - System.out.println("sendMouseEvent: event: "+e); + System.err.println("sendMouseEvent: event: "+e); } ArrayList listeners = null; @@ -840,7 +1187,7 @@ public abstract class Window implements NativeWindow protected void sendKeyEvent(KeyEvent e) { if(DEBUG_KEY_EVENT) { - System.out.println("sendKeyEvent: "+e); + System.err.println("sendKeyEvent: "+e); } ArrayList listeners = null; synchronized(keyListeners) { @@ -904,7 +1251,7 @@ public abstract class Window implements NativeWindow protected void sendWindowEvent(WindowEvent e) { if(DEBUG_WINDOW_EVENT) { - System.out.println("sendWindowEvent: "+e); + System.err.println("sendWindowEvent: "+e); } ArrayList listeners = null; synchronized(windowListeners) { @@ -1027,7 +1374,30 @@ public abstract class Window implements NativeWindow return sb.toString(); } - private RecursiveToolkitLock destructionLock = new RecursiveToolkitLock(); private RecursiveToolkitLock surfaceLock = new RecursiveToolkitLock(); + private RecursiveToolkitLock windowLock = new RecursiveToolkitLock(); + + private static final boolean TRACE_LOCK = false; + + protected final void windowLock() { + getInnerWindow().windowLock.lock(); + if(TRACE_LOCK) { + Exception e = new Exception("WINDOW LOCK SET: R "+getInnerWindow().windowLock.getRecursionCount()+", "+getInnerWindow().windowLock); + e.printStackTrace(); + } + } + protected final void windowUnlock() { + getInnerWindow().windowLock.unlock(); + if(TRACE_LOCK) { + Exception e = new Exception("WINDOW LOCK FREE: R "+getInnerWindow().windowLock.getRecursionCount()+", "+getInnerWindow().windowLock); + e.printStackTrace(); + } + } + protected final boolean windowIsLocked() { + return getInnerWindow().windowLock.isLocked(); + } + protected final void shouldNotCallThis() { + throw new NativeWindowException("Should not call this"); + } } diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java new file mode 100644 index 000000000..23269a93b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2010 Sven Gothel. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name Sven Gothel or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SVEN GOTHEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.newt.awt; + +import java.lang.reflect.*; +import java.security.*; + +import java.awt.Canvas; + +import javax.media.nativewindow.*; +// import javax.media.nativewindow.awt.*; + +import com.jogamp.newt.event.awt.AWTAdapter; +import com.jogamp.newt.event.awt.AWTParentWindowAdapter; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.newt.impl.Debug; + +public class NewtCanvasAWT extends java.awt.Canvas { + public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); + + NativeWindow parent = null; + Window newtChild = null; + AWTAdapter awtAdapter = null; + + /** + * Instantiates a NewtCanvas without a NEWT child.<br> + * @see #setNEWTChild(Window) + */ + public NewtCanvasAWT() { + super(); + } + + /** + * Instantiates a NewtCanvas with a NEWT child. + */ + public NewtCanvasAWT(Window child) { + super(); + setNEWTChild(child); + } + + /** sets a new NEWT child, provoking reparenting on the NEWT level. */ + public NewtCanvasAWT setNEWTChild(Window child) { + if(newtChild!=child) { + newtChild = child; + if(null!=parent) { + // reparent right away, addNotify has been called already + reparentWindow( (null!=newtChild) ? true : false ); + } + } + return this; + } + + /** @return the current NEWT child */ + public Window getNEWTChild() { + return newtChild; + } + + /** @return this AWT Canvas NativeWindow represention, may be null in case {@link #removeNotify()} has been called, + * or {@link #addNotify()} hasn't been called yet.*/ + public NativeWindow getNativeWindow() { return parent; } + + void setWindowAdapter(boolean attach) { + if(null!=awtAdapter) { + awtAdapter.removeFrom(this); + awtAdapter=null; + } + if(attach && null!=newtChild) { + awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this); + } + } + + public void addNotify() { + super.addNotify(); + disableBackgroundErase(); + if(DEBUG_IMPLEMENTATION) { + // if ( isShowing() == false ) -> Container was not visible yet. + // if ( isShowing() == true ) -> Container is already visible. + System.err.println("NewtCanvasAWT.addNotify: "+newtChild+", "+this+", visible "+isVisible()+", showing "+isShowing()+", displayable "+isDisplayable()); + } + reparentWindow(true); + } + + public void removeNotify() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("NewtCanvasAWT.removeNotify: "+newtChild); + } + reparentWindow(false); + super.removeNotify(); + } + + void reparentWindow(boolean add) { + if(null==newtChild) { + return; // nop + } + + if(add) { + if(null!=newtChild) { + parent = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); + } + if(null!=parent) { + // 1st choice - NEWT size := AWT size + // 2nd choice - AWT size := NEWT size + if(0>=getWidth()*getHeight()) { + setSize(newtChild.getWidth(), newtChild.getHeight()); // #2 + } + Screen screen = null; + if( !newtChild.isNativeWindowValid() ) { + screen = NewtFactoryAWT.createCompatibleScreen(parent); + } + newtChild.reparentWindow(parent, screen); + if ( 0 < getWidth() * getHeight() ) { + newtChild.setSize(getWidth(), getHeight()); // #1 + newtChild.setVisible(true); + } + setWindowAdapter(true); + } + } else { + setWindowAdapter(false); + parent = null; + newtChild.setVisible(false); + newtChild.reparentWindow(null, null); + } + } + + // Disables the AWT's erasing of this Canvas's background on Windows + // in Java SE 6. This internal API is not available in previous + // releases, but the system property + // -Dsun.awt.noerasebackground=true can be specified to get similar + // results globally in previous releases. + private static boolean disableBackgroundEraseInitialized; + private static Method disableBackgroundEraseMethod; + private void disableBackgroundErase() { + if (!disableBackgroundEraseInitialized) { + try { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + Class clazz = getToolkit().getClass(); + while (clazz != null && disableBackgroundEraseMethod == null) { + try { + disableBackgroundEraseMethod = + clazz.getDeclaredMethod("disableBackgroundErase", + new Class[] { Canvas.class }); + disableBackgroundEraseMethod.setAccessible(true); + } catch (Exception e) { + clazz = clazz.getSuperclass(); + } + } + } catch (Exception e) { + } + return null; + } + }); + } catch (Exception e) { + } + disableBackgroundEraseInitialized = true; + } + if (disableBackgroundEraseMethod != null) { + try { + disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this }); + } catch (Exception e) { + // FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10) + // throw new GLException(e); + } + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java index e0f86b1a9..6409ab7a8 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java @@ -30,7 +30,7 @@ * SVEN GOTHEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ -package com.jogamp.newt.impl.awt; +package com.jogamp.newt.awt; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; @@ -46,9 +46,12 @@ import com.jogamp.newt.Display; import com.jogamp.newt.Screen; import com.jogamp.newt.Window; import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.newt.impl.Debug; import com.jogamp.common.util.ReflectionUtil; -public class AWTNewtFactory extends NewtFactory { +public class NewtFactoryAWT extends NewtFactory { + public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); /** * Wraps an AWT component into a {@link javax.media.nativewindow.NativeWindow} utilizing the {@link javax.media.nativewindow.NativeWindowFactory},<br> @@ -76,46 +79,13 @@ public class AWTNewtFactory extends NewtFactory { DefaultGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, (Capabilities) capsRequested.clone(), capsRequested); NativeWindow awtNative = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow + if(DEBUG_IMPLEMENTATION) { + System.out.println("NewtFactoryAWT.getNativeWindow: "+awtComp+" -> "+awtNative); + } return awtNative; } - /** - * Creates a native NEWT child window to a AWT parent window.<br> - * <p> - * First we create a {@link javax.media.nativewindow.NativeWindow} presentation of the given {@link java.awt.Component}, - * utilizing {@link #getNativeWindow(java.awt.Component)}.<br> - * The actual wrapping implementation is {@link com.jogamp.nativewindow.impl.jawt.JAWTWindow}.<br></p> - * <p> - * Second we create a child {@link com.jogamp.newt.Window}, - * utilizing {@link com.jogamp.newt.NewtFactory#createWindowImpl(java.lang.String, javax.media.nativewindow.NativeWindow, com.jogamp.newt.Screen, javax.media.nativewindow.Capabilities, boolean)}, - * passing the created {@link javax.media.nativewindow.NativeWindow}.<br></p> - - * <p> - * Third we attach a {@link com.jogamp.newt.event.awt.AWTParentWindowAdapter} to the given AWT component.<br> - * The adapter passes window related events to our new child window, look at the implementation<br></p> - * - * <p> - * Forth we pass the parents visibility to the new Window<br></p> - * - * @param awtParentObject must be of type java.awt.Component - * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always - * @return The successful created child window, or null if the AWT parent is not ready yet (no valid peers) - */ - public static Window createNativeChildWindow(Object awtParentObject, Capabilities newtCaps, boolean undecorated) { - if( null == awtParentObject ) { - throw new NativeWindowException("Null AWT Parent Component"); - } - if( ! (awtParentObject instanceof java.awt.Component) ) { - throw new NativeWindowException("AWT Parent Component not a java.awt.Component"); - } - java.awt.Component awtParent = (java.awt.Component) awtParentObject; - - // Generate a complete JAWT NativeWindow from the AWT Component - NativeWindow parent = getNativeWindow(awtParent, newtCaps); - if(null==parent) { - throw new NativeWindowException("Null NativeWindow from parent: "+awtParent); - } - + public static Screen createCompatibleScreen(NativeWindow parent) { // Get parent's NativeWindow details AWTGraphicsConfiguration parentConfig = (AWTGraphicsConfiguration) parent.getGraphicsConfiguration(); AWTGraphicsScreen parentScreen = (AWTGraphicsScreen) parentConfig.getScreen(); @@ -124,16 +94,7 @@ public class AWTNewtFactory extends NewtFactory { // Prep NEWT's Display and Screen according to the parent final String type = NativeWindowFactory.getNativeWindowType(true); Display display = NewtFactory.wrapDisplay(type, parentDevice.getHandle()); - Screen screen = NewtFactory.createScreen(type, display, parentScreen.getIndex()); - - // NEWT Window creation and add event handler for proper propagation AWT -> NEWT - // and copy size/visible state - Window window = NewtFactory.createWindowImpl(type, parent, screen, newtCaps, undecorated); - new AWTParentWindowAdapter(window).addTo(awtParent); - window.setSize(awtParent.getWidth(), awtParent.getHeight()); - window.setVisible(awtParent.isVisible()); - - return window; + return NewtFactory.createScreen(type, display, parentScreen.getIndex()); } } diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java index 3abe6531a..e8497a741 100644 --- a/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java @@ -31,6 +31,9 @@ */ package com.jogamp.newt.event.awt; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.newt.impl.Debug; + /** * Convenient adapter forwarding AWT events to NEWT via the event listener model.<br> * <p> @@ -102,6 +105,8 @@ package com.jogamp.newt.event.awt; */ public abstract class AWTAdapter implements java.util.EventListener { + public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); + com.jogamp.newt.event.NEWTEventListener newtListener; com.jogamp.newt.Window newtWindow; @@ -157,9 +162,16 @@ public abstract class AWTAdapter implements java.util.EventListener */ public abstract AWTAdapter addTo(java.awt.Component awtComponent); + /** @see #addTo(java.awt.Component) */ + public abstract AWTAdapter removeFrom(java.awt.Component awtComponent); + void enqueueEvent(com.jogamp.newt.event.NEWTEvent event) { + enqueueEvent(false, event); + } + + void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { try { - newtWindow.getScreen().getDisplay().enqueueEvent(event); + newtWindow.getScreen().getDisplay().enqueueEvent(wait, event); } catch (NullPointerException npe) { /* that's ok .. window might be down already */ } diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java index 64d4d8d86..d2b733f98 100644 --- a/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java @@ -50,6 +50,11 @@ public class AWTKeyAdapter extends AWTAdapter implements java.awt.event.KeyListe return this; } + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeKeyListener(this); + return this; + } + public void keyPressed(java.awt.event.KeyEvent e) { com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow); if(null!=newtListener) { diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java index 7efcd123e..058a5f250 100644 --- a/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java @@ -51,6 +51,12 @@ public class AWTMouseAdapter extends AWTAdapter implements java.awt.event.MouseL return this; } + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeMouseListener(this); + awtComponent.removeMouseMotionListener(this); + return this; + } + public void mouseClicked(java.awt.event.MouseEvent e) { com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); if(null!=newtListener) { diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java index 01f0457e3..d94a32a9c 100644 --- a/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java @@ -42,9 +42,18 @@ public class AWTParentWindowAdapter extends AWTWindowAdapter } public void componentResized(java.awt.event.ComponentEvent e) { - // need to really resize the NEWT child window - java.awt.Component comp = e.getComponent(); - newtWindow.setSize(comp.getWidth(), comp.getHeight()); + // Need to resize the NEWT child window + // the resized event will be send via the native window feedback. + final java.awt.Component comp = e.getComponent(); + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + if( 0 < comp.getWidth() * comp.getHeight() ) { + newtWindow.setSize(comp.getWidth(), comp.getHeight()); + newtWindow.setVisible(comp.isVisible()); + } else { + newtWindow.setVisible(false); + } + }}); } public void componentMoved(java.awt.event.ComponentEvent e) { diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java index fd6ceddae..53ce03299 100644 --- a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java @@ -33,9 +33,9 @@ package com.jogamp.newt.event.awt; public class AWTWindowAdapter extends AWTAdapter - implements java.awt.event.ComponentListener, java.awt.event.WindowListener, java.awt.event.HierarchyListener + implements java.awt.event.ComponentListener, java.awt.event.WindowListener, + java.awt.event.HierarchyListener, java.awt.event.HierarchyBoundsListener { - java.awt.Component awtComponent; WindowClosingListener windowClosingListener; public AWTWindowAdapter(com.jogamp.newt.event.WindowListener newtListener) { @@ -51,16 +51,36 @@ public class AWTWindowAdapter } public AWTAdapter addTo(java.awt.Component awtComponent) { - this.awtComponent = awtComponent; + java.awt.Window win = getWindow(awtComponent); awtComponent.addComponentListener(this); awtComponent.addHierarchyListener(this); - addWindowClosingListenerTo(getWindow(awtComponent)); + awtComponent.addHierarchyBoundsListener(this); + if( null == windowClosingListener ) { + windowClosingListener = new WindowClosingListener(); + } + if( null != win ) { + win.addWindowListener(windowClosingListener); + } if(awtComponent instanceof java.awt.Window) { ((java.awt.Window)awtComponent).addWindowListener(this); } return this; } + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeComponentListener(this); + awtComponent.removeHierarchyListener(this); + awtComponent.removeHierarchyBoundsListener(this); + java.awt.Window win = getWindow(awtComponent); + if( null != win && null != windowClosingListener ) { + win.removeWindowListener(windowClosingListener); + } + if(awtComponent instanceof java.awt.Window) { + ((java.awt.Window)awtComponent).removeWindowListener(this); + } + return this; + } + static java.awt.Window getWindow(java.awt.Component comp) { while( null != comp && !(comp instanceof java.awt.Window) ) { comp = comp.getParent(); @@ -71,15 +91,6 @@ public class AWTWindowAdapter return null; } - void addWindowClosingListenerTo(java.awt.Window win) { - if( null == windowClosingListener ) { - windowClosingListener = new WindowClosingListener(); - } - if( null != win ) { - win.addWindowListener(windowClosingListener); - } - } - public void componentResized(java.awt.event.ComponentEvent e) { com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); if(null!=newtListener) { @@ -101,7 +112,11 @@ public class AWTWindowAdapter public void componentShown(java.awt.event.ComponentEvent e) { if(null==newtListener) { if(!newtWindow.isDestroyed()) { - newtWindow.setVisible(true, true /* deferred */); + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + newtWindow.setVisible(true); + } + }); } } } @@ -109,7 +124,11 @@ public class AWTWindowAdapter public void componentHidden(java.awt.event.ComponentEvent e) { if(null==newtListener) { if(!newtWindow.isDestroyed()) { - newtWindow.setVisible(false, true /* deferred */); + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + newtWindow.setVisible(false); + } + }); } } } @@ -145,27 +164,45 @@ public class AWTWindowAdapter public void hierarchyChanged(java.awt.event.HierarchyEvent e) { if( null == newtListener ) { long bits = e.getChangeFlags(); - java.awt.Component changed = e.getChanged(); + final java.awt.Component changed = e.getChanged(); if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & bits ) ) { - final boolean visible = changed.isVisible(); - if(!newtWindow.isDestroyed()) { - newtWindow.setVisible(visible, true /* deferred */); + final boolean showing = changed.isShowing(); + if(DEBUG_IMPLEMENTATION) { + System.out.println("hierarchyChanged SHOWING_CHANGED: showing "+showing+", "+changed); } - } else if( 0 != ( java.awt.event.HierarchyEvent.PARENT_CHANGED & bits ) ) { - if(awtComponent == changed) { - java.awt.Window win = getWindow(changed); - if(null != win) { - addWindowClosingListenerTo(win); - } else { - java.awt.Component parent = e.getChangedParent(); - if(parent instanceof java.awt.Window) { - ((java.awt.Window)parent).removeWindowListener(this); - if( null != windowClosingListener ) { - ((java.awt.Window)parent).removeWindowListener(windowClosingListener); - } + if(!newtWindow.isDestroyed()) { + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + newtWindow.setVisible(showing); } - } + }); } + } + if( 0 != ( java.awt.event.HierarchyEvent.DISPLAYABILITY_CHANGED & bits ) ) { + final boolean displayability = changed.isDisplayable(); + if(DEBUG_IMPLEMENTATION) { + System.out.println("hierarchyChanged DISPLAYABILITY_CHANGED: displayability "+displayability+", "+changed); + } + } + } + } + + public void ancestorMoved(java.awt.event.HierarchyEvent e) { + if( null == newtListener ) { + final java.awt.Component changed = e.getChanged(); + final boolean showing = changed.isShowing(); + if(DEBUG_IMPLEMENTATION) { + System.out.println("ancestorMoved: showing "+showing+", "+changed); + } + } + } + + public void ancestorResized(java.awt.event.HierarchyEvent e) { + if( null == newtListener ) { + final java.awt.Component changed = e.getChanged(); + final boolean showing = changed.isShowing(); + if(DEBUG_IMPLEMENTATION) { + System.out.println("ancestorResized: showing "+showing+", "+changed); } } } @@ -176,7 +213,7 @@ public class AWTWindowAdapter if(null!=newtListener) { ((com.jogamp.newt.event.WindowListener)newtListener).windowDestroyNotify(event); } else { - enqueueEvent(event); + enqueueEvent(true, event); } } diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java index b98a6fa20..f97625320 100644 --- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java @@ -176,7 +176,7 @@ public class AWTWindow extends Window { return res; } - protected void setVisibleImpl() { + protected void setVisibleImpl(final boolean visible) { runOnEDT(true, new Runnable() { public void run() { container.setVisible(visible); @@ -203,13 +203,7 @@ public class AWTWindow extends Window { ((AWTScreen)screen).setScreenSize(w, h); } - public void setSize(final int width, final int height) { - this.width = width; - this.height = height; - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - } + protected void setSizeImpl(final int width, final int height) { if(null!=container) { /** An AWT event on setSize() would bring us in a deadlock situation, hence invokeLater() */ runOnEDT(false, new Runnable() { @@ -237,55 +231,34 @@ public class AWTWindow extends Window { Insets(insets[0],insets[1],insets[2],insets[3]); } - public void setPosition(final int x, final int y) { - this.x = x; - this.y = y; - if(!fullscreen) { - nfs_x=x; - nfs_y=y; + protected void setPositionImpl(final int x, final int y) { + if(null!=container) { + runOnEDT(true, new Runnable() { + public void run() { + container.setLocation(x, y); + } + }); } - runOnEDT(true, new Runnable() { - public void run() { - container.setLocation(x, y); - } - }); } - public boolean setFullscreen(final boolean fullscreen) { - if(this.fullscreen!=fullscreen) { - final int x,y,w,h; - this.fullscreen=fullscreen; - if(fullscreen) { - x = 0; y = 0; - w = screen.getWidth(); - h = screen.getHeight(); - } else { - x = nfs_x; - y = nfs_y; - w = nfs_width; - h = nfs_height; - } - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("AWTWindow fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h); - } - /** An AWT event on setSize() would bring us in a deadlock situation, hence invokeLater() */ - runOnEDT(false, new Runnable() { - public void run() { - if(null!=frame) { - if(!container.isDisplayable()) { - frame.setUndecorated(undecorated||fullscreen); - } else { - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("AWTWindow can't undecorate already created frame"); - } + protected boolean setFullscreenImpl(final boolean fullscreen, final int x, final int y, final int w, final int h) { + /** An AWT event on setSize() would bring us in a deadlock situation, hence invokeLater() */ + runOnEDT(false, new Runnable() { + public void run() { + if(null!=frame) { + if(!container.isDisplayable()) { + frame.setUndecorated(isUndecorated(fullscreen)); + } else { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("AWTWindow can't undecorate already created frame"); } } - container.setLocation(x, y); - container.setSize(w, h); } - }); - } - return true; + container.setLocation(x, y); + container.setSize(w, h); + } + }); + return fullscreen; } public Object getWrappedWindow() { diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java index 7b867db21..74cb53f7e 100644 --- a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java @@ -77,13 +77,13 @@ public class Window extends com.jogamp.newt.Window { } } - protected void setVisibleImpl() { + protected void setVisibleImpl(boolean visible) { if(visible) { ((Display)screen.getDisplay()).setFocus(this); } } - public void setSize(int width, int height) { + protected void setSizeImpl(int width, int height) { Screen screen = (Screen) getScreen(); if((x+width)>screen.getWidth()) { width=screen.getWidth()-x; @@ -91,18 +91,12 @@ public class Window extends com.jogamp.newt.Window { if((y+height)>screen.getHeight()) { height=screen.getHeight()-y; } - this.width = width; - this.height = height; - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - } if(0!=surfaceHandle) { SetBounds0(surfaceHandle, screen.getWidth(), screen.getHeight(), x, y, width, height); } } - public void setPosition(int x, int y) { + protected void setPositionImpl(int x, int y) { Screen screen = (Screen) getScreen(); if((x+width)>screen.getWidth()) { x=screen.getWidth()-width; @@ -110,37 +104,14 @@ public class Window extends com.jogamp.newt.Window { if((y+height)>screen.getHeight()) { y=screen.getHeight()-height; } - this.x = x; - this.y = y; - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - } if(0!=surfaceHandle) { SetBounds0(surfaceHandle, screen.getWidth(), screen.getHeight(), x, y, width, height); } } - public boolean setFullscreen(boolean fullscreen) { - if(this.fullscreen!=fullscreen) { - int x,y,w,h; - this.fullscreen=fullscreen; - if(fullscreen) { - x = 0; y = 0; - w = screen.getWidth(); - h = screen.getHeight(); - } else { - x = nfs_x; - y = nfs_y; - w = nfs_width; - h = nfs_height; - } - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("IntelGDL Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h); - } - if(0!=surfaceHandle) { - SetBounds0(surfaceHandle, screen.getWidth(), screen.getHeight(), x, y, w, h); - } + protected boolean setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + if(0!=surfaceHandle) { + SetBounds0(surfaceHandle, screen.getWidth(), screen.getHeight(), x, y, w, h); } return fullscreen; } diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java index 93c2b14bb..20a181096 100755 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java @@ -153,12 +153,17 @@ public class MacWindow extends Window { public void run() { nsViewLock.lock(); try { - if(DEBUG_IMPLEMENTATION) System.out.println("MacWindow.CloseAction "+Thread.currentThread().getName()); + if(DEBUG_IMPLEMENTATION) { System.out.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } if (windowHandle != 0) { close0(windowHandle); - windowHandle = 0; + } + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("closeNative failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); } } finally { + windowHandle = 0; nsViewLock.unlock(); } } @@ -191,7 +196,7 @@ public class MacWindow extends Window { public void run() { nsViewLock.lock(); try { - createWindow(false); + createWindow(false, getX(), getY(), getWidth(), getHeight(), isFullscreen()); } finally { nsViewLock.unlock(); } @@ -229,30 +234,26 @@ public class MacWindow extends Window { nsViewLock.unlock(); } - class VisibleAction implements Runnable { - public void run() { - nsViewLock.lock(); - try { - if(DEBUG_IMPLEMENTATION) System.out.println("MacWindow.VisibleAction "+visible+" "+Thread.currentThread().getName()); - if (visible) { - createWindow(false); - if (windowHandle != 0) { - makeKeyAndOrderFront0(windowHandle); - } - } else { - if (windowHandle != 0) { - orderOut0(windowHandle); + protected void setVisibleImpl(final boolean visible) { + MainThread.invoke(true, new Runnable() { + public void run() { + nsViewLock.lock(); + try { + if (visible) { + createWindow(false, getX(), getY(), getWidth(), getHeight(), isFullscreen()); + if (windowHandle != 0) { + makeKeyAndOrderFront0(windowHandle); + } + } else { + if (windowHandle != 0) { + orderOut0(windowHandle); + } } + } finally { + nsViewLock.unlock(); } - } finally { - nsViewLock.unlock(); } - } - } - private VisibleAction visibleAction = new VisibleAction(); - - protected void setVisibleImpl() { - MainThread.invoke(true, visibleAction); + }); } class TitleAction implements Runnable { @@ -307,20 +308,9 @@ public class MacWindow extends Window { } private SizeAction sizeAction = new SizeAction(); - public void setSize(int width, int height) { - if (width != this.width || this.height != height) { - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - if (0 != windowHandle) { - // this width/height will be set by sizeChanged, called by OSX - MainThread.invoke(true, sizeAction); - } else { - this.width=width; - this.height=height; - } - } - } + protected void setSizeImpl(int width, int height) { + // this width/height will be set by sizeChanged, called by OSX + MainThread.invoke(true, sizeAction); } class PositionAction implements Runnable { @@ -337,56 +327,28 @@ public class MacWindow extends Window { } private PositionAction positionAction = new PositionAction(); - public void setPosition(int x, int y) { - if ( this.x != x || this.y != y ) { - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - if (0 != windowHandle) { - // this x/y will be set by positionChanged, called by OSX - MainThread.invoke(true, positionAction); - } else { - this.x=x; - this.y=y; - } - } - } + protected void setPositionImpl(int x, int y) { + // this x/y will be set by positionChanged, called by OSX + MainThread.invoke(true, positionAction); } - class FullscreenAction implements Runnable { - public void run() { - nsViewLock.lock(); - try { - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("MacWindow fs: "+fullscreen+" "+x+"/"+y+" "+width+"x"+height); - } - createWindow(true); - if (windowHandle != 0) { - makeKeyAndOrderFront0(windowHandle); + protected boolean setFullscreenImpl(final boolean fullscreen, final int x, final int y, final int w, final int h) { + MainThread.invoke(true, new Runnable() { + public void run() { + nsViewLock.lock(); + try { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("MacWindow fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h); + } + createWindow(true, x, y, w, h, fullscreen); + if (windowHandle != 0) { + makeKeyAndOrderFront0(windowHandle); + } + } finally { + nsViewLock.unlock(); } - } finally { - nsViewLock.unlock(); } - } - } - private FullscreenAction fullscreenAction = new FullscreenAction(); - - public boolean setFullscreen(boolean fullscreen) { - if(this.fullscreen!=fullscreen) { - this.fullscreen=fullscreen; - if(fullscreen) { - x = 0; - y = 0; - width = screen.getWidth(); - height = screen.getHeight(); - } else { - x = nfs_x; - y = nfs_y; - width = nfs_width; - height = nfs_height; - } - MainThread.invoke(true, fullscreenAction); - } + }); return fullscreen; } @@ -538,7 +500,7 @@ public class MacWindow extends Window { super.sendKeyEvent(eventType, modifiers, key, keyChar); } - private void createWindow(boolean recreate) { + private void createWindow(boolean recreate, int x, int y, int width, int height, boolean fullscreen) { if(0!=windowHandle && !recreate) { return; } @@ -554,8 +516,8 @@ public class MacWindow extends Window { surfaceHandle = 0; } windowHandle = createWindow0(parentWindowHandle, - getX(), getY(), getWidth(), getHeight(), fullscreen, - (isUndecorated() ? + x, y, width, height, fullscreen, + (isUndecorated(fullscreen) ? NSBorderlessWindowMask : NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), NSBackingStoreBuffered, diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java index b25ed4ee8..7d3a0ac8c 100755 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java @@ -70,32 +70,24 @@ public class Window extends com.jogamp.newt.Window { } } - protected void setVisibleImpl() { } + protected void setVisibleImpl(boolean visible) { } - public void setSize(int width, int height) { - System.err.println("setSize "+width+"x"+height+" n/a in BroadcomEGL"); - } - - void setSizeImpl(int width, int height) { + protected void setSizeImpl(int width, int height) { if(0!=windowHandle) { // n/a in BroadcomEGL System.err.println("BCEGL Window.setSizeImpl n/a in BroadcomEGL with realized window"); } else { - if(DEBUG_IMPLEMENTATION) { - Exception e = new Exception("BCEGL Window.setSizeImpl() "+this.width+"x"+this.height+" -> "+width+"x"+height); - e.printStackTrace(); - } this.width = width; this.height = height; } } - public void setPosition(int x, int y) { + protected void setPositionImpl(int x, int y) { // n/a in BroadcomEGL - System.err.println("setPosition n/a in BroadcomEGL"); + System.err.println("BCEGL Window.setPositionImpl n/a in BroadcomEGL"); } - public boolean setFullscreen(boolean fullscreen) { + protected boolean setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { // n/a in BroadcomEGL System.err.println("setFullscreen n/a in BroadcomEGL"); return false; diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java index f60abb7cd..54623996c 100755 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java @@ -85,30 +85,26 @@ public class KDWindow extends Window { } } - protected void setVisibleImpl() { + protected void setVisibleImpl(boolean visible) { setVisible0(eglWindowHandle, visible); - clearEventMask(); } - public void setSize(int width, int height) { + protected void setSizeImpl(int width, int height) { if(0!=eglWindowHandle) { setSize0(eglWindowHandle, width, height); } } - public void setPosition(int x, int y) { + protected void setPositionImpl(int x, int y) { // n/a in KD System.err.println("setPosition n/a in KD"); } - public boolean setFullscreen(boolean fullscreen) { - if(0!=eglWindowHandle && this.fullscreen!=fullscreen) { - this.fullscreen=fullscreen; - if(this.fullscreen) { - setFullScreen0(eglWindowHandle, true); - } else { - setFullScreen0(eglWindowHandle, false); - setSize0(eglWindowHandle, nfs_width, nfs_height); + protected boolean setFullscreenImpl(final boolean fullscreen, final int x, final int y, final int w, final int h) { + if(0!=eglWindowHandle) { + setFullScreen0(eglWindowHandle, fullscreen); + if(!fullscreen) { + setSize0(eglWindowHandle, w, h); } } return true; diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java index dad3456d7..5e1b5a43c 100755 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java @@ -131,13 +131,28 @@ public class WindowsWindow extends Window { protected void closeNative() { if (hdc != 0) { if(windowHandleClose != 0) { - ReleaseDC0(windowHandleClose, hdc); + try { + ReleaseDC0(windowHandleClose, hdc); + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("closeNative failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } } hdc = 0; } if(windowHandleClose != 0) { - DestroyWindow0(windowHandleClose); - windowHandleClose = 0; + try { + DestroyWindow0(windowHandleClose); + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("closeNative failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } finally { + windowHandleClose = 0; + } } } @@ -146,66 +161,32 @@ public class WindowsWindow extends Window { super.windowDestroyed(); } - protected void setVisibleImpl() { + protected void setVisibleImpl(boolean visible) { setVisible0(windowHandle, visible); } - // @Override - public void setSize(int width, int height) { - if (width != this.width || this.height != height) { - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - if(0!=windowHandle) { - // this width/height will be set by sizeChanged, called by Windows - setSize0(parentWindowHandle, windowHandle, x, y, width, height); - } else { - this.width=width; - this.height=height; - } - } - } + protected void setSizeImpl(int width, int height) { + // this width/height will be set by sizeChanged, called by Windows + setSize0(parentWindowHandle, windowHandle, x, y, width, height); } - //@Override - public void setPosition(int x, int y) { - if ( this.x != x || this.y != y ) { - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - if(0!=windowHandle) { - // this x/y will be set by positionChanged, called by Windows - setPosition0(parentWindowHandle, windowHandle, x , y /*, width, height*/); - } else { - this.x=x; - this.y=y; - } - } - } + protected void setPositionImpl(int x, int y) { + // this x/y will be set by positionChanged, called by Windows + setPosition0(parentWindowHandle, windowHandle, x , y /*, width, height*/); } - public boolean setFullscreen(boolean fullscreen) { - if(0!=windowHandle && (this.fullscreen!=fullscreen)) { - int x,y,w,h; - this.fullscreen=fullscreen; - if(fullscreen) { - x = 0; y = 0; - w = screen.getWidth(); - h = screen.getHeight(); - } else { - x = nfs_x; - y = nfs_y; - w = nfs_width; - h = nfs_height; - } - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("WindowsWindow fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h); - } - setFullscreen0(parentWindowHandle, windowHandle, x, y, w, h, undecorated, fullscreen); - } + protected boolean setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + setFullscreen0(fullscreen?0:parentWindowHandle, windowHandle, x, y, w, h, isUndecorated(fullscreen)); return fullscreen; } + protected boolean reparentWindowImpl() { + if(0!=windowHandle) { + reparentWindow0(fullscreen?0:parentWindowHandle, windowHandle, x, y, width, height, isUndecorated()); + } + return true; + } + // @Override public void requestFocus() { super.requestFocus(); @@ -245,7 +226,8 @@ public class WindowsWindow extends Window { private static native void setVisible0(long windowHandle, boolean visible); private native void setSize0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height); private static native void setPosition0(long parentWindowHandle, long windowHandle, int x, int y /*, int width, int height*/); - private native void setFullscreen0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, boolean isUndecorated, boolean on); + private native void setFullscreen0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, boolean isUndecorated); + private native void reparentWindow0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, boolean isUndecorated); private static native void setTitle0(long windowHandle, String title); private static native void requestFocus0(long windowHandle); diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java index 085d1cab7..a51eee241 100755 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java @@ -55,13 +55,12 @@ public class X11Window extends Window { if (config == null) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } - attachedToParent = 0 != parentWindowHandle ; X11GraphicsConfiguration x11config = (X11GraphicsConfiguration) config; long visualID = x11config.getVisualID(); long w = CreateWindow0(parentWindowHandle, display.getHandle(), screen.getIndex(), visualID, display.getJavaObjectAtom(), display.getWindowDeleteAtom(), - x, y, width, height, undecorated()); + x, y, width, height, isUndecorated()); if (w == 0 || w!=windowHandle) { throw new NativeWindowException("Error creating window: "+w); } @@ -72,9 +71,17 @@ public class X11Window extends Window { protected void closeNative() { if(0!=displayHandleClose && 0!=windowHandleClose && null!=getScreen() ) { X11Display display = (X11Display) getScreen().getDisplay(); - CloseWindow0(displayHandleClose, windowHandleClose, display.getJavaObjectAtom()); - windowHandleClose = 0; - displayHandleClose = 0; + try { + CloseWindow0(displayHandleClose, windowHandleClose, display.getJavaObjectAtom()); + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("closeNative failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } finally { + windowHandleClose = 0; + displayHandleClose = 0; + } } } @@ -84,72 +91,33 @@ public class X11Window extends Window { super.windowDestroyed(); } - protected void setVisibleImpl() { + protected void setVisibleImpl(boolean visible) { setVisible0(getDisplayHandle(), windowHandle, visible); - clearEventMask(); } - public void setSize(int width, int height) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("X11Window setSize: "+this.width+"x"+this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+windowHandle); - } - if (width != this.width || this.height != height) { - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - if(0!=windowHandle) { - // this width/height will be set by windowChanged, called by X11 - setSize0(getDisplayHandle(), windowHandle, width, height); - } else { - this.width = width; - this.height = height; - } - } - } + protected void setSizeImpl(int width, int height) { + // this width/height will be set by windowChanged, called by X11 + setSize0(getDisplayHandle(), windowHandle, width, height); } - public void setPosition(int x, int y) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("X11Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+windowHandle); - } - if ( this.x != x || this.y != y ) { - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - if(0!=windowHandle) { - // this x/y will be set by windowChanged, called by X11 - setPosition0(parentWindowHandle, getDisplayHandle(), windowHandle, x, y); - } else { - this.x = x; - this.y = y; - } - } - } + protected void setPositionImpl(int x, int y) { + // this x/y will be set by windowChanged, called by X11 + setPosition0(parentWindowHandle, getDisplayHandle(), windowHandle, x, y); } - public boolean setFullscreen(boolean fullscreen) { - if(0!=windowHandle && this.fullscreen!=fullscreen) { - int x,y,w,h; - this.fullscreen=fullscreen; - if(fullscreen) { - x = 0; y = 0; - w = screen.getWidth(); - h = screen.getHeight(); - } else { - x = nfs_x; - y = nfs_y; - w = nfs_width; - h = nfs_height; - } - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+undecorated()); - } - setPosSizeDecor0(fullscreen?0:parentWindowHandle, getDisplayHandle(), getScreenIndex(), windowHandle, x, y, w, h, undecorated()); - } + protected boolean setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + setPosSizeDecor0(fullscreen?0:parentWindowHandle, getDisplayHandle(), getScreenIndex(), windowHandle, x, y, w, h, isUndecorated(fullscreen)); return fullscreen; } - final boolean undecorated() { return attachedToParent || undecorated || fullscreen ; } + protected boolean reparentWindowImpl() { + if(0!=windowHandle) { + reparentWindow0(fullscreen?0:parentWindowHandle, getDisplayHandle(), getScreenIndex(), windowHandle, x, y, isUndecorated()); + // X11 reparent unmaps the window + setVisibleImpl(visible); + } + return true; + } // @Override public void requestFocus() { @@ -187,6 +155,8 @@ public class X11Window extends Window { private native void setTitle0(long display, long windowHandle, String title); private native void requestFocus0(long display, long windowHandle); private native void setPosition0(long parentWindowHandle, long display, long windowHandle, int x, int y); + private native void reparentWindow0(long parentWindowHandle, long display, int screen_index, long windowHandle, + int x, int y, boolean undecorated); private void windowChanged(int newX, int newY, int newWidth, int newHeight) { if(width != newWidth || height != newHeight) { @@ -226,14 +196,17 @@ public class X11Window extends Window { } } + /** + * @param focusGained + */ + private void visibleChanged(boolean visible) { + // FIXME .. this.visible = visible ; + } + private void windowCreated(long windowHandle) { this.windowHandle = windowHandle; } private long windowHandleClose; private long displayHandleClose; - private boolean attachedToParent; - - // non fullscreen dimensions .. - private int nfs_width, nfs_height, nfs_x, nfs_y; } diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index b5d55aebd..2bb28466c 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -35,6 +35,7 @@ package com.jogamp.newt.opengl; import com.jogamp.newt.*; import com.jogamp.newt.event.*; +import com.jogamp.nativewindow.impl.RecursiveToolkitLock; import javax.media.nativewindow.*; import javax.media.opengl.*; import com.jogamp.opengl.impl.GLDrawableHelper; @@ -53,19 +54,15 @@ import java.util.*; * <p> */ public class GLWindow extends Window implements GLAutoDrawable { - private static List/*GLWindow*/ glwindows = new ArrayList(); - - private boolean ownerOfWinScrDpy; private Window window; private boolean runPumpMessages; /** * Constructor. Do not call this directly -- use {@link #create()} instead. */ - protected GLWindow(Window window, boolean ownerOfWinScrDpy) { - this.ownerOfWinScrDpy = ownerOfWinScrDpy; + protected GLWindow(Window window) { this.window = window; - this.window.setAutoDrawableClient(true); + this.window.setHandleDestroyNotify(false); this.runPumpMessages = ( null == getScreen().getDisplay().getEDTUtil() ) ; window.addWindowListener(new WindowAdapter() { public void windowResized(WindowEvent e) { @@ -76,10 +73,6 @@ public class GLWindow extends Window implements GLAutoDrawable { sendDestroy = true; } }); - - List newglw = (List) ((ArrayList) glwindows).clone(); - newglw.add(this); - glwindows=newglw; } /** Creates a new GLWindow attaching the given window - not owning the Window. */ @@ -87,10 +80,10 @@ public class GLWindow extends Window implements GLAutoDrawable { return create(null, window, null, false); } - /** Creates a new GLWindow attaching a new native child Window of the given <code>parentWindowObject</code> + /** Creates a new GLWindow attaching a new native child Window of the given <code>parentNativeWindow</code> with the given GLCapabilities - owning the Window */ - public static GLWindow create(Object parentWindowObject, GLCapabilities caps) { - return create(parentWindowObject, null, caps, true); + public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilities caps) { + return create(parentNativeWindow, null, caps, false); } /** Creates a new GLWindow attaching a new decorated Window on the local display, screen 0, with a @@ -106,27 +99,29 @@ public class GLWindow extends Window implements GLAutoDrawable { } /** Either or: window (prio), or caps and undecorated (2nd choice) */ - private static GLWindow create(Object parentWindowObject, Window window, + private static GLWindow create(NativeWindow parentNativeWindow, Window window, GLCapabilities caps, boolean undecorated) { - boolean ownerOfWinScrDpy=false; if (window == null) { if (caps == null) { caps = new GLCapabilities(null); // default .. } - ownerOfWinScrDpy = true; - window = NewtFactory.createWindow(parentWindowObject, caps, undecorated); + window = NewtFactory.createWindow(parentNativeWindow, caps, undecorated); } - return new GLWindow(window, ownerOfWinScrDpy); + return new GLWindow(window); } + public boolean isNativeWindowValid() { + return (null!=window)?window.isNativeWindowValid():false; + } + public boolean isDestroyed() { - return null == window ; + return (null!=window)?window.isDestroyed():true; } - public Window getWindow() { - return window; + public Window getInnerWindow() { + return window.getInnerWindow(); } /** @@ -162,67 +157,66 @@ public class GLWindow extends Window implements GLAutoDrawable { shouldNotCallThis(); } - protected void dispose(boolean regenerate, boolean sendEvent) { + protected void dispose() { if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - Exception e1 = new Exception("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", 1"); + Exception e1 = new Exception("GLWindow.dispose() "+Thread.currentThread()+", start: "+this); e1.printStackTrace(); } - if(sendEvent) { - sendDisposeEvent(); + if ( null != context && null != drawable && drawable.isRealized() ) { + helper.invokeGL(drawable, context, disposeAction, null); } if (context != null) { context.destroy(); + context = null; } if (drawable != null) { drawable.setRealized(false); - } - - if(regenerate) { - if(null==window) { - throw new GLException("GLWindow.dispose(true): null window"); - } - - // recreate GLDrawable, to reflect the new graphics configurations - NativeWindow nw; - if (window.getWrappedWindow() != null) { - nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); - } else { - nw = window; - } - drawable = factory.createGLDrawable(nw); - drawable.setRealized(true); - context = drawable.createContext(null); - sendReshape = true; // ensure a reshape event is send .. + drawable = null; } if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - System.out.println("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", fin: "+this); + System.out.println("GLWindow.dispose() "+Thread.currentThread()+", fin: "+this); } } - public synchronized void destroy() { - destroy(true); - } - - /** @param sendDisposeEvent should be false in a [time,reliable] critical shutdown */ - public synchronized void destroy(boolean sendDisposeEvent) { - List newglw = (List) ((ArrayList) glwindows).clone(); - newglw.remove(this); - glwindows=newglw; + class DestroyAction implements Runnable { + boolean deep; + public DestroyAction(boolean deep) { + this.deep = deep; + } + public void run() { + windowLock(); + try { + if(null==window || window.isDestroyed()) { + return; // nop + } + dispose(); - dispose(false, sendDisposeEvent); + if(null!=window) { + window.destroy(deep); + } - if(null!=window) { - if(ownerOfWinScrDpy) { - window.destroy(true); + if(deep) { + helper=null; + } + } finally { + windowUnlock(); } } + } - drawable = null; - context = null; - window = null; + /** + * @param deep If true, all resources, ie listeners, parent handles, size, position + * and the referenced NEWT screen and display, will be destroyed as well. Be aware that if you call + * this method with deep = true, you will not be able to regenerate the Window. + * @see #destroy() + */ + public void destroy(boolean deep) { + if(!isDestroyed()) { + runOnEDTIfAvail(true, new DestroyAction(deep)); + } } public boolean getPerfLogEnabled() { return perfLog; } @@ -231,28 +225,61 @@ public class GLWindow extends Window implements GLAutoDrawable { perfLog = v; } - protected void setVisibleImpl() { + protected void setVisibleImpl(boolean visible) { shouldNotCallThis(); } - public void setVisible(final boolean visible) { - window.setVisible(visible); - if (visible && null == context && 0 != window.getWindowHandle()) { - NativeWindow nw; - if (window.getWrappedWindow() != null) { - nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); - } else { - nw = window; + public void reparentWindow(NativeWindow newParent, Screen newScreen) { + window.reparentWindow(newParent, newScreen); + } + + class VisibleAction implements Runnable { + boolean visible; + public VisibleAction(boolean visible) { + this.visible = visible; + } + public void run() { + windowLock(); + try{ + window.setVisible(visible); + if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) { + NativeWindow nw; + if (window.getWrappedWindow() != null) { + nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); + } else { + nw = window; + } + GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + if(null==factory) { + factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); + } + if(null==drawable) { + drawable = factory.createGLDrawable(nw); + } + drawable.setRealized(true); + context = drawable.createContext(null); + sendReshape = true; // ensure a reshape event is send .. + } + } finally { + windowUnlock(); } - GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); - factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); - drawable = factory.createGLDrawable(nw); - drawable.setRealized(true); - context = drawable.createContext(null); - sendReshape = true; // ensure a reshape event is send .. } } + public void setVisible(boolean visible) { + if(!isDestroyed()) { + runOnEDTIfAvail(true, new VisibleAction(visible)); + } + } + + public Capabilities getRequestedCapabilities() { + return window.getRequestedCapabilities(); + } + + public NativeWindow getParentNativeWindow() { + return window.getParentNativeWindow(); + } + public Screen getScreen() { return window.getScreen(); } @@ -277,21 +304,31 @@ public class GLWindow extends Window implements GLAutoDrawable { window.requestFocus(); } + public Insets getInsets() { + return window.getInsets(); + } + public void setSize(int width, int height) { window.setSize(width, height); } + protected void setSizeImpl(int width, int height) { + shouldNotCallThis(); + } public void setPosition(int x, int y) { window.setPosition(x, y); } - - public Insets getInsets() { - return window.getInsets(); + protected void setPositionImpl(int x, int y) { + shouldNotCallThis(); } public boolean setFullscreen(boolean fullscreen) { return window.setFullscreen(fullscreen); } + protected boolean setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + shouldNotCallThis(); + return false; + } public boolean isVisible() { return window.isVisible(); @@ -317,6 +354,10 @@ public class GLWindow extends Window implements GLAutoDrawable { return window.isFullscreen(); } + public void sendEvent(NEWTEvent e) { + window.sendEvent(e); + } + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { window.addSurfaceUpdatedListener(l); } @@ -333,10 +374,6 @@ public class GLWindow extends Window implements GLAutoDrawable { window.surfaceUpdated(updater, window, when); } - public void sendEvent(NEWTEvent e) { - window.sendEvent(e); - } - public void addMouseListener(MouseListener l) { window.addMouseListener(l); } @@ -437,14 +474,11 @@ public class GLWindow extends Window implements GLAutoDrawable { setVisible(true); } - if( null != context ) { + if( window.isNativeWindowValid() && null != context ) { if(runPumpMessages) { window.getScreen().getDisplay().pumpMessages(); } - if(window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) { - dispose(true, true); - } - if (sendDestroy) { + if(sendDestroy || window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) { destroy(); sendDestroy=false; } else if ( window.isVisible() ) { @@ -456,12 +490,6 @@ public class GLWindow extends Window implements GLAutoDrawable { } } - private void sendDisposeEvent() { - if(drawable!=null && context != null) { - helper.invokeGL(drawable, context, disposeAction, null); - } - } - /** This implementation uses a static value */ public void setAutoSwapBufferMode(boolean onOrOff) { helper.setAutoSwapBufferMode(onOrOff); @@ -555,24 +583,24 @@ public class GLWindow extends Window implements GLAutoDrawable { // NativeWindow/Window methods // - public synchronized int lockSurface() throws NativeWindowException { + public int lockSurface() throws NativeWindowException { if(null!=drawable) return drawable.getNativeWindow().lockSurface(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + return window.lockSurface(); } - public synchronized void unlockSurface() { + public void unlockSurface() { if(null!=drawable) drawable.getNativeWindow().unlockSurface(); - else throw new NativeWindowException("NEWT-GLWindow not locked"); + else window.unlockSurface(); } - public synchronized boolean isSurfaceLocked() { + public boolean isSurfaceLocked() { if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked(); - return false; + return window.isSurfaceLocked(); } - public synchronized Exception getLockedStack() { + public Exception getLockedStack() { if(null!=drawable) return drawable.getNativeWindow().getLockedStack(); - return null; + return window.getLockedStack(); } public boolean surfaceSwap() { @@ -614,6 +642,10 @@ public class GLWindow extends Window implements GLAutoDrawable { public void setRealized(boolean realized) { } + public boolean isRealized() { + return ( null != drawable ) ? drawable.isRealized() : false; + } + public GLCapabilities getChosenGLCapabilities() { if (drawable == null) { throw new GLException("No drawable yet"); @@ -629,12 +661,4 @@ public class GLWindow extends Window implements GLAutoDrawable { return drawable.getGLProfile(); } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private void shouldNotCallThis() { - throw new NativeWindowException("Should not call this"); - } } diff --git a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java index e6af747c8..235132460 100644 --- a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java @@ -54,7 +54,7 @@ public class EDTUtil { public EDTUtil(ThreadGroup tg, String name, Runnable pumpMessages) { this.threadGroup = tg; - this.name=new String("EDT-"+name); + this.name=new String(Thread.currentThread().getName()+"-"+"EDT-"+name); this.pumpMessages=pumpMessages; } @@ -123,15 +123,15 @@ public class EDTUtil { } public void invokeAndWait(Runnable task) { - invoke(false, task); + invoke(true, task); } - public void invoke(boolean deferred, Runnable task) { + public void invoke(boolean wait, Runnable task) { if(task == null) { return; } invokeLater(task); - if(!deferred) { + if(wait) { waitOnWorker(); } } diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index 1956b6899..6e8599d92 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -60,15 +60,28 @@ void setFrameTopLeftPoint(NSWindow* pwin, NSWindow* win, jint x, jint y) NSRect visibleRect; // either screen or parent-window NSPoint pt; int d_pty=0; // parent titlebar height + int d_ptx=0; if(NULL==pwin) { visibleRect = [screen frame]; } else { visibleRect = [pwin frame]; - NSView* pview = [pwin contentView]; NSRect viewRect = [pview frame]; d_pty = visibleRect.size.height - viewRect.size.height; + //d_pty = visibleRect.origin.y - viewRect.size.height; + //d_ptx = visibleRect.size.height - viewRect.size.height; + fprintf(stderr, "pwin %lf/%lf %lfx%lf, pview %lf/%lf %lfx%lf -> %d/%d\n", + visibleRect.origin.x, + visibleRect.origin.y, + visibleRect.size.width, + visibleRect.size.height, + viewRect.origin.x, + viewRect.origin.y, + viewRect.size.width, + viewRect.size.height, + x, y); + } pt = NSMakePoint(visibleRect.origin.x + x, visibleRect.origin.y + visibleRect.size.height - y - d_pty); @@ -167,8 +180,6 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_macosx_MacDisplay_dispatchMessa NS_DURING - NSWindow* win = NULL; - NewtView* view = NULL; int num_events = 0; // Periodically take a break @@ -287,7 +298,17 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_macosx_MacWindow_createWindow0 backing: (NSBackingStoreType) bufferingType screen: screen] retain]; - NSWindow* parentWindow = (NSWindow*) ((intptr_t) parent); + NSObject *nsParentObj = (NSObject*) ((intptr_t) parent); + NSWindow* parentWindow = NULL; + if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSWindow class]] ) { + parentWindow = (NSWindow*) nsParentObj; + } else if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSView class]] ) { + NSView* view = (NSView*) nsParentObj; + parentWindow = [view window]; + fprintf(stderr, "createWindow0 - Parent is NSView : %p -> %p (win) \n", nsParentObj, parentWindow); + } else { + fprintf(stderr, "createWindow0 - Parent is neither NSWindow nor NSView : %p\n", nsParentObj); + } if(NULL!=parentWindow) { [parentWindow addChildWindow: window ordered: NSWindowAbove]; [window setParentWindow: parentWindow]; @@ -448,7 +469,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_macosx_MacWindow_changeContent [pool release]; - return oldView; + return (jlong) ((intptr_t) oldView); } /* diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index fabcab1c7..37fd9c621 100755 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -1034,7 +1034,7 @@ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getHeight /* * Class: com_jogamp_newt_impl_windows_WindowsWindow - * Method: initIDs + * Method: initIDs0 * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_initIDs0 @@ -1282,10 +1282,10 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setPositi /* * Class: com_jogamp_newt_impl_windows_WindowsWindow * Method: setFullscreen - * Signature: (JIIIIZZ)V + * Signature: (JIIIIZ)V */ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullscreen0 - (JNIEnv *env, jobject obj, jlong parent, jlong window, jint x, jint y, jint width, jint height, jboolean bIsUndecorated, jboolean on) + (JNIEnv *env, jobject obj, jlong parent, jlong window, jint x, jint y, jint width, jint height, jboolean bIsUndecorated) { UINT flags; HWND hwndP = (HWND) (intptr_t) parent; @@ -1293,10 +1293,55 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullsc HWND hWndInsertAfter; DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; - if ( JNI_TRUE == on ) { - hwndP = NULL; // full-screen is top level + // order of call sequence: (MS documentation) + // SetParent(.., NULL), SetWindowLong ( WS_POPUP ) + // SetParent(.., PARENT), SetWindowLong ( WS_CHILD ) + if ( NULL == hwndP ) { + SetParent(hwnd, NULL); + } + + if(NULL!=hwndP) { + windowStyle |= WS_CHILD ; + } else if (bIsUndecorated) { + windowStyle |= WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; + } else { + windowStyle |= WS_OVERLAPPEDWINDOW; + } + SetWindowLong(hwnd, GWL_STYLE, windowStyle); + + if ( NULL != hwndP ) { + SetParent(hwnd, hwndP ); + } + + if ( NULL == hwndP ) { + flags = SWP_SHOWWINDOW; + hWndInsertAfter = HWND_TOPMOST; + } else { + flags = SWP_NOACTIVATE | SWP_NOZORDER; + hWndInsertAfter = 0; } + SetWindowPos(hwnd, hWndInsertAfter, x, y, width, height, flags); + + NewtWindows_requestFocus ( hwnd ); + + (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) width, (jint) height); +} + +/* + * Class: com_jogamp_newt_impl_windows_WindowsWindow + * Method: reparentWindow0 + * Signature: (JIIIIZ)V + */ +JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_reparentWindow0 + (JNIEnv *env, jobject obj, jlong parent, jlong window, jint x, jint y, jint width, jint height, jboolean bIsUndecorated) +{ + UINT flags; + HWND hwndP = (HWND) (intptr_t) parent; + HWND hwnd = (HWND) (intptr_t) window; + HWND hWndInsertAfter; + DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + // order of call sequence: (MS documentation) // SetParent(.., NULL), SetWindowLong ( WS_POPUP ) // SetParent(.., PARENT), SetWindowLong ( WS_CHILD ) @@ -1306,7 +1351,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullsc if(NULL!=hwndP) { windowStyle |= WS_CHILD ; - } else if (bIsUndecorated || on) { + } else if (bIsUndecorated) { windowStyle |= WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; } else { windowStyle |= WS_OVERLAPPEDWINDOW; @@ -1317,7 +1362,8 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullsc SetParent(hwnd, hwndP ); } - if(on==JNI_TRUE) { + /** + if ( NULL == hwndP ) { flags = SWP_SHOWWINDOW; hWndInsertAfter = HWND_TOPMOST; } else { @@ -1326,10 +1372,11 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullsc } SetWindowPos(hwnd, hWndInsertAfter, x, y, width, height, flags); + */ NewtWindows_requestFocus ( hwnd ); - (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) width, (jint) height); + // (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) width, (jint) height); } /* diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index abaa3594f..f77f54cd1 100755 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -69,6 +69,7 @@ #define DBG_PRINT6(str, arg1, arg2, arg3, arg4, arg5, arg6) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6); #define DBG_PRINT7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7); #define DBG_PRINT8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + #define DBG_PRINT9(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) fprintf(stderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); #define DUMP_VISUAL_INFO(a,b) _dumpVisualInfo((a),(b)) @@ -105,6 +106,7 @@ #define DBG_PRINT6(str, arg1, arg2, arg3, arg4, arg5, arg6) #define DBG_PRINT7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define DBG_PRINT8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + #define DBG_PRINT9(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) #define DUMP_VISUAL_INFO(a,b) @@ -173,6 +175,7 @@ static jclass newtWindowClz=NULL; static jmethodID windowChangedID = NULL; static jmethodID focusChangedID = NULL; +static jmethodID visibleChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowDestroyedID = NULL; static jmethodID windowCreatedID = NULL; @@ -312,6 +315,13 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_CompleteDisplay0 (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom); } +/** + * Window + */ + +// #define WINDOW_EVENT_MASK ( FocusChangeMask | StructureNotifyMask | ExposureMask | VisibilityNotify ) +#define WINDOW_EVENT_MASK ( FocusChangeMask | StructureNotifyMask | VisibilityNotify ) + static int putPtrIn32Long(unsigned long * dst, uintptr_t src) { int i=0; dst[i++] = (unsigned long) ( ( src >> 0 ) & 0xFFFFFFFF ) ; @@ -344,7 +354,7 @@ static void setJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlon (unsigned char *)&jogl_java_object_data, nitems_32); } -static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom) { +static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning) { Atom actual_type_return; int actual_format_return; int nitems_32 = ( sizeof(uintptr_t) == 8 ) ? 2 : 1 ; @@ -362,14 +372,18 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j &nitems_return, &bytes_after_return, &jogl_java_object_data_pp); if ( Success != res ) { - fprintf(stderr, "Warning: NEWT X11Window: Could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, result 0!\n", res, nitems_return, bytes_after_return); + if(True==showWarning) { + fprintf(stderr, "Warning: NEWT X11Window: Could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, result 0!\n", res, nitems_return, bytes_after_return); + } return NULL; } if(actual_type_return!=(Atom)javaObjectAtom || nitems_return<nitems_32 || NULL==jogl_java_object_data_pp) { XFree(jogl_java_object_data_pp); - fprintf(stderr, "Warning: NEWT X11Window: Fetched invalid Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, actual_type_return %ld, JOGL_JAVA_OBJECT %ld, result 0!\n", + if(True==showWarning) { + fprintf(stderr, "Warning: NEWT X11Window: Fetched invalid Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, actual_type_return %ld, JOGL_JAVA_OBJECT %ld, result 0!\n", res, nitems_return, bytes_after_return, (long)actual_type_return, javaObjectAtom); + } return NULL; } } @@ -385,29 +399,50 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j return jwindow; } -static void NewtWindows_requestFocus (Display *dpy, Window w) { - XWindowAttributes attributes; - - XLockDisplay(dpy) ; - +static void NewtWindows_requestFocus0 (Display *dpy, Window w, XWindowAttributes *xwa) { // Avoid 'BadMatch' errors from XSetInputFocus, ie if window is not viewable - XGetWindowAttributes(dpy, w, &attributes); - if(attributes.map_state == IsViewable) { + if(xwa->map_state == IsViewable) { XSetInputFocus(dpy, w, RevertToParent, CurrentTime); - XSync(dpy, False); } +} + +static void NewtWindows_requestFocus1 (Display *dpy, Window w) { + XWindowAttributes xwa; + + XLockDisplay(dpy) ; + + XGetWindowAttributes(dpy, w, &xwa); + NewtWindows_requestFocus0 (dpy, w, &xwa); + XSync(dpy, False); XUnlockDisplay(dpy) ; } -/** changing this attribute while a window is established, - * didn't impact the decoration - only at window creation time. -static void NewtWindows_setOverrideRedirect (Display *dpy, Window w, Bool val) { +/** + * Changing this attribute while a window is established, + * returns the previous value. + */ +static Bool NewtWindows_setOverrideRedirect0 (Display *dpy, Window w, XWindowAttributes *xwa, Bool newVal) { + Bool oldVal = xwa->override_redirect; XSetWindowAttributes xswa; - memset(&xswa, 0, sizeof(XSetWindowAttributes)); - xswa.override_redirect = val; - XChangeWindowAttributes(dpy, w, CWOverrideRedirect, &xswa); -} */ + + if(oldVal != newVal) { + memset(&xswa, 0, sizeof(XSetWindowAttributes)); + xswa.override_redirect = newVal; + XChangeWindowAttributes(dpy, w, CWOverrideRedirect, &xswa); + } + return oldVal; +} + +static Bool NewtWindows_setOverrideRedirect1 (Display *dpy, Window w, Bool newVal) { + XWindowAttributes xwa; + Bool oldVal; + + XSync(dpy, False); + XGetWindowAttributes(dpy, w, &xwa); + + return NewtWindows_setOverrideRedirect0 (dpy, w, &xwa, newVal); +} #define MWM_HINTS_DECORATIONS (1L << 1) #define PROP_MWM_HINTS_ELEMENTS 5 @@ -469,18 +504,26 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages return ; } + DBG_PRINT3( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, evt.type); + displayDispatchErrorHandlerEnable(1, env); - jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom); + jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, + #ifdef VERBOSE_ON + True + #else + False + #endif + ); displayDispatchErrorHandlerEnable(0, env); if(NULL==jwindow) { - fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for invalid X11 window %p\n", + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)dpy, evt.type, (void*)evt.xany.window); + XUnlockDisplay(dpy) ; - // DBG_PRINT1( "X11: DispatchMessages 0x%X - Leave 2\n", dpy); - return; + continue; } switch(evt.type) { @@ -497,11 +540,10 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages } XUnlockDisplay(dpy) ; - // DBG_PRINT3( "X11: DispatchMessages 0x%X - Window %p, Event %d\n", dpy, jwindow, evt.type); switch(evt.type) { case ButtonPress: - NewtWindows_requestFocus ( dpy, evt.xany.window ); + NewtWindows_requestFocus1 ( dpy, evt.xany.window ); (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, (jint) evt.xbutton.state, (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); @@ -565,6 +607,16 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE); break; + case MapNotify: + DBG_PRINT1( "X11: event . MapNotify call 0x%X\n", (unsigned int)evt.xunmap.window); + // FIXME (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_TRUE); + break; + + case UnmapNotify: + DBG_PRINT1( "X11: event . UnmapNotify call 0x%X\n", (unsigned int)evt.xunmap.window); + // FIXME (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE); + break; + // unhandled events .. yet .. case VisibilityNotify: @@ -574,9 +626,6 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages DBG_PRINT1( "X11: event . Expose call 0x%X\n", (unsigned int)evt.xexpose.window); /* FIXME: Might want to send a repaint event .. */ break; - case UnmapNotify: - DBG_PRINT1( "X11: event . UnmapNotify call 0x%X\n", (unsigned int)evt.xunmap.window); - break; default: DBG_PRINT3("X11: event . unhandled %d 0x%X call 0x%X\n", evt.type, evt.type, (unsigned int)evt.xunmap.window); } @@ -644,6 +693,7 @@ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_x11_X11Window_initIDs0 { windowChangedID = (*env)->GetMethodID(env, clazz, "windowChanged", "(IIII)V"); focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(Z)V"); + visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(Z)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); windowDestroyedID = (*env)->GetMethodID(env, clazz, "windowDestroyed", "()V"); windowCreatedID = (*env)->GetMethodID(env, clazz, "windowCreated", "(J)V"); @@ -652,6 +702,7 @@ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_x11_X11Window_initIDs0 if (windowChangedID == NULL || focusChangedID == NULL || + visibleChangedID == NULL || windowDestroyNotifyID == NULL || windowDestroyedID == NULL || windowCreatedID == NULL || @@ -691,8 +742,6 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 Screen* scrn; Atom wm_delete_atom; - DBG_PRINT5( "X11: CreateWindow %x/%d %dx%d, undeco %d\n", x, y, width, height, undecorated); - if(dpy==NULL) { _FatalError(env, "invalid display connection.."); } @@ -707,6 +756,11 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 XSync(dpy, False); scrn = ScreenOfDisplay(dpy, scrn_idx); + if(0==windowParent) { + windowParent = XRootWindowOfScreen(scrn); + } + DBG_PRINT7( "X11: CreateWindow dpy %p, parent %p, %x/%d %dx%d, undeco %d\n", + (void*)dpy, (void*)windowParent, x, y, width, height, undecorated); // try given VisualID on screen memset(&visualTemplate, 0, sizeof(XVisualInfo)); @@ -721,8 +775,8 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 XFree(pVisualQuery); pVisualQuery=NULL; } - DBG_PRINT5( "X11: [CreateWindow] trying given (dpy %p, screen %d, visualID: %d, parent 0x%X) found: %p\n", - dpy, scrn_idx, (int)visualID, (unsigned int)windowParent, visual); + DBG_PRINT5( "X11: [CreateWindow] trying given (dpy %p, screen %d, visualID: %d, parent %p) found: %p\n", + dpy, scrn_idx, (int)visualID, (void*)windowParent, visual); if (visual==NULL) { @@ -735,17 +789,12 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 pVisualQuery=NULL; } - if(0==windowParent) { - windowParent = XRootWindowOfScreen(scrn); - } - - attrMask = ( CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect ) ; + attrMask = ( CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect ) ; memset(&xswa, 0, sizeof(xswa)); - xswa.override_redirect = ( JNI_TRUE == undecorated || 0 != parent ) ? True : False ; + xswa.override_redirect = ( 0 != parent ) ? True : False ; xswa.border_pixel = 0; xswa.background_pixel = 0; - xswa.event_mask = FocusChangeMask | ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask; xswa.colormap = XCreateColormap(dpy, windowParent, // XRootWindow(dpy, scrn_idx), visual, @@ -778,10 +827,12 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 long xevent_mask = 0; xevent_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask; xevent_mask |= KeyPressMask | KeyReleaseMask; - xevent_mask |= FocusChangeMask | ExposureMask | StructureNotifyMask | VisibilityNotify ; + xevent_mask |= WINDOW_EVENT_MASK ; XSelectInput(dpy, window, xevent_mask); } + NewtWindows_setDecorations (dpy, window, ( JNI_TRUE == undecorated ) ? False : True ); + XSync(dpy, False); XUnlockDisplay(dpy) ; @@ -808,7 +859,9 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CloseWindow0 } XLockDisplay(dpy) ; - jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom); + DBG_PRINT2( "X11: CloseWindow START dpy %p, win %p\n", (void*)dpy, (void*)w); + + jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom, True); if(NULL==jwindow) { _throwNewRuntimeException(dpy, env, "could not fetch Java Window object, bail out!"); return; @@ -825,6 +878,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CloseWindow0 XDestroyWindow(dpy, w); XSync(dpy, False); + DBG_PRINT0( "X11: CloseWindow END\n"); XUnlockDisplay(dpy) ; (*env)->CallVoidMethod(env, obj, windowDestroyedID); @@ -886,8 +940,63 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setSize0 /* * Class: com_jogamp_newt_impl_x11_X11Window + * Method: setPosition0 + * Signature: (JJII)V + */ +JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosition0 + (JNIEnv *env, jobject obj, jlong parent, jlong display, jlong window, jint x, jint y) +{ + Display * dpy = (Display *) (intptr_t) display; + Window w = (Window)window; + XWindowChanges xwc; + + DBG_PRINT2( "X11: setPos0 . XConfigureWindow %d/%d\n", x, y); + if(dpy==NULL) { + _FatalError(env, "invalid display connection.."); + } + XLockDisplay(dpy) ; + + memset(&xwc, 0, sizeof(XWindowChanges)); + xwc.x=x; + xwc.y=y; + XConfigureWindow(dpy, w, CWX|CWY, &xwc); + XSync(dpy, False); + + XUnlockDisplay(dpy) ; +} + +static void NewtWindows_reparentWindow + (Display * dpy, Screen * scrn, Window w, XWindowAttributes *xwa, jlong jparent, jint x, jint y, jboolean undecorated) +{ + Window parent = (0!=jparent)?(Window)jparent:XRootWindowOfScreen(scrn); + + DBG_PRINT7( "X11: reparentWindow dpy %p, parent %p/%p, win %p, %d/%d undec %d\n", + (void*)dpy, (void*) jparent, (void*)parent, (void*)w, x, y, undecorated); + + // let parent ignore reparent request + NewtWindows_setOverrideRedirect0 (dpy, w, xwa, True); + if(JNI_TRUE == undecorated) { + NewtWindows_setDecorations (dpy, w, False); + } + XSync(dpy, False); + + XReparentWindow( dpy, w, parent, x, y ); + XRaiseWindow(dpy, w); + XSync(dpy, False); + + NewtWindows_setOverrideRedirect0 (dpy, w, xwa, ( 0 != jparent ) ? True : False ); + if(JNI_FALSE == undecorated) { + NewtWindows_setDecorations (dpy, w, True); + } + XSync(dpy, False); + + DBG_PRINT0( "X11: reparentWindow X\n"); +} + +/* + * Class: com_jogamp_newt_impl_x11_X11Window * Method: setPosSizeDecor0 - * Signature: (JIJIIIIIZ)V + * Signature: (JJIJIIIIZ)V */ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosSizeDecor0 (JNIEnv *env, jobject obj, jlong jparent, jlong display, jint screen_index, jlong window, @@ -896,23 +1005,22 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosSizeDecor0 Display * dpy = (Display *) (intptr_t) display; Window w = (Window)window; Screen * scrn = ScreenOfDisplay(dpy, (int)screen_index); - Window parent = (0!=jparent)?(Window)jparent:XRootWindowOfScreen(scrn); XWindowChanges xwc; + XWindowAttributes xwa; - DBG_PRINT5( "X11: setPosSizeDecor0 %d/%d %dx%d, undec %d\n", x, y, width, height, undecorated); + DBG_PRINT8( "X11: setPosSizeDecor0 dpy %p, parent %p, win %p, %d/%d %dx%d undec %d\n", + (void*)dpy, (void*) jparent, (void*)w, x, y, width, height, undecorated); if(dpy==NULL) { _FatalError(env, "invalid display connection.."); } XLockDisplay(dpy) ; - // we need to reparent the window, - // to allow a child window to go fullscreen and back. - XReparentWindow( dpy, w, parent, x, y ); - XRaiseWindow(dpy, w); + XSync(dpy, False); + XGetWindowAttributes(dpy, w, &xwa); - NewtWindows_setDecorations (dpy, w, ( JNI_TRUE == undecorated ) ? False : True ); + NewtWindows_reparentWindow(dpy, scrn, w, &xwa, jparent, x, y, undecorated); memset(&xwc, 0, sizeof(XWindowChanges)); xwc.x=x; @@ -922,35 +1030,39 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosSizeDecor0 XConfigureWindow(dpy, w, CWX|CWY|CWWidth|CWHeight, &xwc); XSync(dpy, False); - NewtWindows_requestFocus ( dpy, w ); + NewtWindows_requestFocus0 ( dpy, w, &xwa ); + XSync(dpy, False); XUnlockDisplay(dpy) ; } /* * Class: com_jogamp_newt_impl_x11_X11Window - * Method: setPosition0 - * Signature: (JJII)V + * Method: reparentWindow0 + * Signature: (JJIJIIZ)V */ -JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosition0 - (JNIEnv *env, jobject obj, jlong parent, jlong display, jlong window, jint x, jint y) +JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_reparentWindow0 + (JNIEnv *env, jobject obj, jlong jparent, jlong display, jint screen_index, jlong window, jint x, jint y, jboolean undecorated) { Display * dpy = (Display *) (intptr_t) display; Window w = (Window)window; - XWindowChanges xwc; + Screen * scrn = ScreenOfDisplay(dpy, (int)screen_index); + XWindowAttributes xwa; + + DBG_PRINT6( "X11: reparentWindow0 dpy %p, parent %p, win %p, %d/%d undec %d\n", + (void*)dpy, (void*) jparent, (void*)w, x, y, undecorated); - DBG_PRINT2( "X11: setPos0 . XConfigureWindow %d/%d\n", x, y); if(dpy==NULL) { _FatalError(env, "invalid display connection.."); } XLockDisplay(dpy) ; - memset(&xwc, 0, sizeof(XWindowChanges)); - xwc.x=x; - xwc.y=y; - XConfigureWindow(dpy, w, CWX|CWY, &xwc); XSync(dpy, False); + XGetWindowAttributes(dpy, w, &xwa); + + NewtWindows_reparentWindow(dpy, scrn, w, &xwa, jparent, x, y, undecorated); XUnlockDisplay(dpy) ; + DBG_PRINT0( "X11: reparentWindow0 X\n"); } /* |