diff options
author | Sven Gothel <[email protected]> | 2010-04-13 20:48:50 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-04-13 20:48:50 +0200 |
commit | 1c1053c6a8b669c067ae1316b9770871e213ea05 (patch) | |
tree | af4ed7ea0b41ea6626cc0ad2208b495733b4056e /src | |
parent | 98de1d96e77a1c1aad237a8e5c6c63e21bcb5fc2 (diff) |
NEWT X11 Fix (mainly ATI and multithreading)
- EventDispatchThread -> EDTUtil
Since the name leads to the assumptions that an instance is the EDT.
EDTUtil manages the EDT within.
- EDTUtil, no more reference to Display, but use a Runnable for the
pumpMessage()
- Window.destroy() check if already done
- X11Window: Added XErrorHandler to catch BadWindow and BadAtom
while dispatching events - it is possible that the resource
is already freed. Also added an XIOErrorHandler to identify
the fatal Display* inaccessibility.
Tests:
- New junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java
Testing creation/destruction and double destruction (error case)
- Fix: src/junit/com/jogamp/test/junit/jogl/offscreen/TestOffscreen01NEWT.java
Properly holding all NEWT references ..
Misc:
- Reduced redundant NEWT 'toString()' output (*Capabilities, ..)
-
Diffstat (limited to 'src')
-rwxr-xr-x | src/junit/com/jogamp/test/junit/jogl/offscreen/TestOffscreen01NEWT.java | 82 | ||||
-rwxr-xr-x | src/junit/com/jogamp/test/junit/jogl/offscreen/WindowUtilNEWT.java | 67 | ||||
-rwxr-xr-x | src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java | 174 | ||||
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/Display.java | 47 | ||||
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/Window.java | 63 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/opengl/GLWindow.java | 6 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/util/EDTUtil.java (renamed from src/newt/classes/com/jogamp/newt/util/EventDispatchThread.java) | 92 | ||||
-rwxr-xr-x | src/newt/native/X11Window.c | 75 |
8 files changed, 443 insertions, 163 deletions
diff --git a/src/junit/com/jogamp/test/junit/jogl/offscreen/TestOffscreen01NEWT.java b/src/junit/com/jogamp/test/junit/jogl/offscreen/TestOffscreen01NEWT.java index 277b41af3..436167dbf 100755 --- a/src/junit/com/jogamp/test/junit/jogl/offscreen/TestOffscreen01NEWT.java +++ b/src/junit/com/jogamp/test/junit/jogl/offscreen/TestOffscreen01NEWT.java @@ -66,38 +66,102 @@ public class TestOffscreen01NEWT { @Test public void test01OffscreenWindow() { - GLWindow windowOffscreen = WindowUtilNEWT.createGLWindow(caps, width, height, false, true, false); - GLEventListener demo = new RedSquare(); + GLCapabilities caps2 = WindowUtilNEWT.fixCaps(caps, false, true, false); + + Display display = NewtFactory.createDisplay(null); // local display + Assert.assertNotNull(display); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + Assert.assertNotNull(screen); + Window window = NewtFactory.createWindow(screen, caps2, false /* undecorated */); + Assert.assertNotNull(window); + window.setSize(width, height); + GLWindow windowOffScreen = GLWindow.create(window); + Assert.assertNotNull(windowOffScreen); + windowOffScreen.setVisible(true); + GLWindow windowOnScreen = null; WindowListener wl=null; MouseListener ml=null; SurfaceUpdatedListener ul=null; - WindowUtilNEWT.run(windowOffscreen, null, windowOnScreen, wl, ml, ul, 2, false /*snapshot*/, false /*debug*/); + WindowUtilNEWT.run(windowOffScreen, null, windowOnScreen, wl, ml, ul, 2, false /*snapshot*/, false /*debug*/); try { Thread.sleep(1000); // 1000 ms } catch (Exception e) {} - WindowUtilNEWT.shutdown(windowOffscreen, windowOnScreen); + + if(null!=windowOnScreen) { + windowOnScreen.destroy(); + } + if(null!=windowOffScreen) { + windowOffScreen.destroy(); + } + if(null!=screen) { + screen.destroy(); + } + if(null!=display) { + display.destroy(); + } } @Test public void test02OffscreenSnapshotWithDemo() { - GLWindow windowOffscreen = WindowUtilNEWT.createGLWindow(caps, width, height, false, true, false); - GLEventListener demo = new RedSquare(); + GLCapabilities caps2 = WindowUtilNEWT.fixCaps(caps, false, true, false); + + Display display = NewtFactory.createDisplay(null); // local display + Assert.assertNotNull(display); + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + Assert.assertNotNull(screen); + Window window = NewtFactory.createWindow(screen, caps2, false /* undecorated */); + Assert.assertNotNull(window); + window.setSize(width, height); + GLWindow windowOffScreen = GLWindow.create(window); + Assert.assertNotNull(windowOffScreen); + windowOffScreen.setVisible(true); + GLWindow windowOnScreen = null; WindowListener wl=null; MouseListener ml=null; SurfaceUpdatedListener ul=null; - WindowUtilNEWT.run(windowOffscreen, demo, windowOnScreen, wl, ml, ul, 2, true /*snapshot*/, false /*debug*/); + GLEventListener demo = new RedSquare(); + Assert.assertNotNull(demo); + + WindowUtilNEWT.run(windowOffScreen, demo, windowOnScreen, wl, ml, ul, 2, true /*snapshot*/, false /*debug*/); try { Thread.sleep(1000); // 1000 ms } catch (Exception e) {} - WindowUtilNEWT.shutdown(windowOffscreen, windowOnScreen); + + if(null!=windowOnScreen) { + windowOnScreen.destroy(); + } + if(null!=windowOffScreen) { + windowOffScreen.destroy(); + } + if(null!=screen) { + screen.destroy(); + } + if(null!=display) { + display.destroy(); + } } public static void main(String args[]) { - org.junit.runner.JUnitCore.main(TestOffscreen01NEWT.class.getName()); + String tstname = TestOffscreen01NEWT.class.getName(); + try { + 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" } ); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/src/junit/com/jogamp/test/junit/jogl/offscreen/WindowUtilNEWT.java b/src/junit/com/jogamp/test/junit/jogl/offscreen/WindowUtilNEWT.java index 26b13cf7d..f6a6dc4be 100755 --- a/src/junit/com/jogamp/test/junit/jogl/offscreen/WindowUtilNEWT.java +++ b/src/junit/com/jogamp/test/junit/jogl/offscreen/WindowUtilNEWT.java @@ -34,6 +34,8 @@ package com.jogamp.test.junit.jogl.offscreen; import com.jogamp.test.junit.util.*; +import org.junit.Assert; + import java.lang.reflect.*; import javax.media.opengl.*; import javax.media.nativewindow.*; @@ -42,52 +44,29 @@ import com.jogamp.newt.opengl.*; public class WindowUtilNEWT { - public static Window createWindow(GLCapabilities caps, int w, int h, boolean onscreen, boolean pbuffer, boolean undecorated) { - GLCapabilities caps2 = (GLCapabilities) caps.clone(); - caps2.setOnscreen(onscreen); - caps2.setPBuffer(!onscreen && pbuffer); - caps2.setDoubleBuffered(!onscreen); - - Display display = NewtFactory.createDisplay(null); // local display - Screen screen = NewtFactory.createScreen(display, 0); // screen 0 - Window window = NewtFactory.createWindow(screen, caps2, onscreen && undecorated); - - GLCapabilities glCaps = (GLCapabilities) window.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); - - GLDrawableFactory factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); - GLDrawable drawable = factory.createGLDrawable(window); - drawable.setRealized(true); - GLContext context = drawable.createContext(null); - - window.setSize(w, h); - window.setVisible(true); - return window; - } - - public static GLWindow createGLWindow(GLCapabilities caps, int w, int h, boolean onscreen, boolean pbuffer, boolean undecorated) { + public static GLCapabilities fixCaps(GLCapabilities caps, boolean onscreen, boolean pbuffer, boolean undecorated) { GLCapabilities caps2 = (GLCapabilities) caps.clone(); caps2.setOnscreen(onscreen); caps2.setPBuffer(!onscreen && pbuffer); caps2.setDoubleBuffered(!onscreen); - GLWindow window = GLWindow.create(caps2, onscreen && undecorated); - window.setSize(w, h); - window.setVisible(true); - return window; + return caps2; } - public static void run(GLWindow windowOffscreen, GLEventListener demo, + public static void run(GLWindow windowOffScreen, GLEventListener demo, GLWindow windowOnScreen, WindowListener wl, MouseListener ml, SurfaceUpdatedListener ul, int frames, boolean snapshot, boolean debug) { try { + Assert.assertNotNull(windowOffScreen); + if(debug && null!=demo) { MiscUtils.setField(demo, "glDebug", new Boolean(true)); MiscUtils.setField(demo, "glTrace", new Boolean(true)); } if(null!=demo) { - if(!MiscUtils.setField(demo, "window", windowOffscreen)) { - MiscUtils.setField(demo, "glWindow", windowOffscreen); + if(!MiscUtils.setField(demo, "window", windowOffScreen)) { + MiscUtils.setField(demo, "glWindow", windowOffScreen); } - windowOffscreen.addGLEventListener(demo); + windowOffScreen.addGLEventListener(demo); } if ( null != windowOnScreen ) { @@ -100,47 +79,35 @@ public class WindowUtilNEWT { windowOnScreen.setVisible(true); } - GLDrawable readDrawable = windowOffscreen.getContext().getGLDrawable() ; + GLDrawable readDrawable = windowOffScreen.getContext().getGLDrawable() ; if ( null == windowOnScreen ) { if(snapshot) { Surface2File s2f = new Surface2File(); - windowOffscreen.addSurfaceUpdatedListener(s2f); + windowOffScreen.addSurfaceUpdatedListener(s2f); } } else { ReadBuffer2Screen readDemo = new ReadBuffer2Screen( readDrawable ) ; windowOnScreen.addGLEventListener(readDemo); } if(null!=ul) { - windowOffscreen.addSurfaceUpdatedListener(ul); + windowOffScreen.addSurfaceUpdatedListener(ul); } if(debug) { System.out.println("+++++++++++++++++++++++++++"); - System.out.println(windowOffscreen); + System.out.println(windowOffScreen); System.out.println("+++++++++++++++++++++++++++"); } - while ( windowOffscreen.getTotalFrames() < frames) { - windowOffscreen.display(); + while ( windowOffScreen.getTotalFrames() < frames) { + windowOffScreen.display(); } - windowOffscreen.removeAllSurfaceUpdatedListener(); + windowOffScreen.removeAllSurfaceUpdatedListener(); } catch (GLException e) { e.printStackTrace(); } } - public static void shutdown(GLWindow windowOffscreen, GLWindow windowOnscreen) { - // Shut things down cooperatively - if(null!=windowOnscreen) { - windowOnscreen.destroy(); - } - if(null!=windowOffscreen) { - windowOffscreen.destroy(); - } - if(null!=windowOnscreen) { - windowOnscreen.getFactory().shutdown(); - } - } } diff --git a/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java new file mode 100755 index 000000000..91760ae80 --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestWindows01NEWT.java @@ -0,0 +1,174 @@ +/* + * 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 com.jogamp.newt.*; + +public class TestWindows01NEWT { + static int width, height; + + @BeforeClass + public static void initClass() { + width = 640; + height = 480; + } + + static Window createWindow(Screen screen, Capabilities 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 + // + Window window = NewtFactory.createWindow(screen, caps, onscreen && undecorated); + Assert.assertNotNull(window); + window.setSize(width, height); + Assert.assertTrue(false==window.isVisible()); + window.setVisible(true); + Assert.assertTrue(true==window.isVisible()); + Assert.assertTrue(width==window.getWidth()); + Assert.assertTrue(height==window.getHeight()); + // System.out.println("Created: "+window); + + // + // Create native OpenGL resources .. XGL/WGL/CGL .. + // equivalent to GLAutoDrawable methods: setVisible(true) + // + caps = (Capabilities) window.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + Assert.assertNotNull(caps); + Assert.assertTrue(caps.getGreenBits()>5); + Assert.assertTrue(caps.getBlueBits()>5); + Assert.assertTrue(caps.getRedBits()>5); + Assert.assertTrue(caps.isOnscreen()==onscreen); + + return window; + } + + static void destroyWindow(Display display, Screen screen, Window window) { + if(null!=window) { + window.destroy(); + } + if(null!=screen) { + screen.destroy(); + } + if(null!=display) { + display.destroy(); + } + } + + @Test + public void testWindowDecor01Simple() { + 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 */); + try { + Thread.sleep(1000); // 1000 ms + } catch (Exception e) {} + destroyWindow(display, screen, window); + } + + @Test + public void testWindowDecor02DestroyWinTwiceA() { + 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 */); + try { + Thread.sleep(1000); // 1000 ms + } catch (Exception e) {} + destroyWindow(null, null, window); + destroyWindow(display, screen, window); + } + + @Test + public void testWindowDecor03TwoWin() { + 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 window1 = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); + Window window2 = createWindow(screen, caps, width, height, true /* onscreen */, false /* undecorated */); + try { + Thread.sleep(1000); // 1000 ms + } catch (Exception e) {} + destroyWindow(null, null, window2); + destroyWindow(display, screen, window1); + } + + public static void main(String args[]) { + String tstname = TestWindows01NEWT.class.getName(); + try { + 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" } ); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 88f6dd34b..2bc99475c 100755 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -35,7 +35,7 @@ package com.jogamp.newt; import javax.media.nativewindow.*; import com.jogamp.newt.impl.Debug; -import com.jogamp.newt.util.EventDispatchThread; +import com.jogamp.newt.util.EDTUtil; import java.util.*; public abstract class Display { @@ -141,11 +141,16 @@ public abstract class Display { display.refCount=1; if(NewtFactory.useEDT()) { - Thread current = Thread.currentThread(); - display.eventDispatchThread = new EventDispatchThread(display, current.getThreadGroup(), current.getName()); - display.eventDispatchThread.start(); final Display f_dpy = display; - display.eventDispatchThread.invokeAndWait(new Runnable() { + Thread current = Thread.currentThread(); + display.edtUtil = new EDTUtil(current.getThreadGroup(), + "Display_"+display.getName()+"-"+current.getName(), + new Runnable() { + public void run() { + f_dpy.pumpMessagesImpl(); + } } ); + display.edt = display.edtUtil.start(); + display.edtUtil.invokeAndWait(new Runnable() { public void run() { f_dpy.createNative(); } @@ -189,7 +194,7 @@ public abstract class Display { } } - public EventDispatchThread getEDT() { return eventDispatchThread; } + public EDTUtil getEDTUtil() { return edtUtil; } public synchronized void destroy() { if(DEBUG) { @@ -201,10 +206,10 @@ public abstract class Display { if(DEBUG) { System.err.println("Display.destroy("+name+") REMOVE: "+this+" "+Thread.currentThread()); } - if(null!=eventDispatchThread) { + if(null!=edtUtil) { final Display f_dpy = this; - final EventDispatchThread f_edt = eventDispatchThread; - eventDispatchThread.invokeAndWait(new Runnable() { + final EDTUtil f_edt = edtUtil; + edtUtil.invokeAndWait(new Runnable() { public void run() { f_dpy.closeNative(); f_edt.stop(); @@ -213,9 +218,9 @@ public abstract class Display { } else { closeNative(); } - if(null!=eventDispatchThread) { - eventDispatchThread.waitUntilStopped(); - eventDispatchThread=null; + if(null!=edtUtil) { + edtUtil.waitUntilStopped(); + edtUtil=null; } aDevice = null; } else { @@ -246,14 +251,13 @@ public abstract class Display { return aDevice; } - public void pumpMessages() { - if(null!=eventDispatchThread) { - dispatchMessages(); - } else { - synchronized(this) { - dispatchMessages(); - } - } + public synchronized void pumpMessages() { + pumpMessagesImpl(); + } + + private void pumpMessagesImpl() { + if(0==refCount) return; + dispatchMessages(); } public String toString() { @@ -268,7 +272,8 @@ public abstract class Display { /** Default impl. nop - Currently only X11 needs a Display lock */ protected void unlockDisplay() { } - protected EventDispatchThread eventDispatchThread = null; + protected EDTUtil edtUtil = null; + protected Thread edt = null; protected String name; protected int refCount; protected AbstractGraphicsDevice aDevice; diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 171bb2468..8f09ae364 100755 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -34,7 +34,7 @@ package com.jogamp.newt; import com.jogamp.newt.impl.Debug; -import com.jogamp.newt.util.EventDispatchThread; +import com.jogamp.newt.util.EDTUtil; import javax.media.nativewindow.*; import com.jogamp.nativewindow.impl.NWReflection; @@ -98,10 +98,10 @@ public abstract class Window implements NativeWindow window.invalidate(); window.screen = screen; window.setUndecorated(undecorated||0!=parentWindowHandle); - EventDispatchThread edt = screen.getDisplay().getEDT(); - if(null!=edt) { + EDTUtil edtUtil = screen.getDisplay().getEDTUtil(); + if(null!=edtUtil) { final Window f_win = window; - edt.invokeAndWait(new Runnable() { + edtUtil.invokeAndWait(new Runnable() { public void run() { f_win.createNative(parentWindowHandle, caps); } @@ -131,10 +131,10 @@ public abstract class Window implements NativeWindow window.invalidate(); window.screen = screen; window.setUndecorated(undecorated); - EventDispatchThread edt = screen.getDisplay().getEDT(); - if(null!=edt) { + EDTUtil edtUtil = screen.getDisplay().getEDTUtil(); + if(null!=edtUtil) { final Window f_win = window; - edt.invokeAndWait(new Runnable() { + edtUtil.invokeAndWait(new Runnable() { public void run() { f_win.createNative(0, caps); } @@ -212,15 +212,15 @@ public abstract class Window implements NativeWindow public String toString() { StringBuffer sb = new StringBuffer(); - sb.append(getClass().getName()+"[config "+config+ - ", windowHandle "+toHexString(getWindowHandle())+ - ", surfaceHandle "+toHexString(getSurfaceHandle())+ - ", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ - ", visible "+isVisible()+ - ", undecorated "+undecorated+ - ", fullscreen "+fullscreen+ + sb.append(getClass().getName()+"[Config "+config+ + ", WindowHandle "+toHexString(getWindowHandle())+ + ", SurfaceHandle "+toHexString(getSurfaceHandle())+ + ", Pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ + ", Visible "+isVisible()+ + ", Undecorated "+undecorated+ + ", Fullscreen "+fullscreen+ ", "+screen+ - ", wrappedWindow "+getWrappedWindow()); + ", WrappedWindow "+getWrappedWindow()); sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); for (Iterator iter = surfaceUpdatedListeners.iterator(); iter.hasNext(); ) { @@ -343,25 +343,28 @@ public abstract class Window implements NativeWindow keyListeners = new ArrayList(); } synchronized(this) { - destructionLock.lock(); try { - Screen scr = screen; - Display dpy = (null!=screen) ? screen.getDisplay() : null; - EventDispatchThread edt = (null!=dpy) ? dpy.getEDT() : null; - if(null!=edt) { - final Window f_win = this; - edt.invokeAndWait(new Runnable() { - public void run() { - f_win.closeNative(); - } - } ); - } else { - closeNative(); + destructionLock.lock(); + 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(); + } } invalidate(); if(deep) { - if(null!=scr) { - scr.destroy(); + if(null!=screen) { + screen.destroy(); } if(null!=dpy) { dpy.destroy(); diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 4a7f27f3a..fec70c99c 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -65,7 +65,7 @@ public class GLWindow extends Window implements GLAutoDrawable { this.ownerOfWinScrDpy = ownerOfWinScrDpy; this.window = window; this.window.setAutoDrawableClient(true); - this.runPumpMessages = ( null == getScreen().getDisplay().getEDT() ) ; + this.runPumpMessages = ( null == getScreen().getDisplay().getEDTUtil() ) ; window.addWindowListener(new WindowListener() { public void windowResized(WindowEvent e) { sendReshape = true; @@ -152,7 +152,7 @@ public class GLWindow extends Window implements GLAutoDrawable { * @deprecated EXPERIMENTAL, semantic is about to be removed after further verification. */ public void setRunPumpMessages(boolean onoff) { - if( onoff && null!=getScreen().getDisplay().getEDT() ) { + if( onoff && null!=getScreen().getDisplay().getEDTUtil() ) { throw new GLException("GLWindow.setRunPumpMessages(true) - Can't do with EDT on"); } runPumpMessages = onoff; @@ -382,7 +382,7 @@ public class GLWindow extends Window implements GLAutoDrawable { } public String toString() { - return "NEWT-GLWindow[ \n\tDrawable: "+drawable+", \n\tWindow: "+window+", \n\tHelper: "+helper+", \n\tFactory: "+factory+"]"; + return "NEWT-GLWindow[ \n\tHelper: "+helper+", \n\tDrawable: "+drawable + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]"; } //---------------------------------------------------------------------- diff --git a/src/newt/classes/com/jogamp/newt/util/EventDispatchThread.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java index 675c6f322..f852bcf5c 100644 --- a/src/newt/classes/com/jogamp/newt/util/EventDispatchThread.java +++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java @@ -40,30 +40,30 @@ import com.jogamp.newt.Display; import com.jogamp.newt.impl.Debug; import java.util.*; -public class EventDispatchThread { +public class EDTUtil { public static final boolean DEBUG = Debug.debug("EDT"); private ThreadGroup threadGroup; private volatile boolean shouldStop = false; - private TaskWorker taskWorker = null; - private Object taskWorkerLock = new Object(); + private EventDispatchThread edt = null; + private Object edtLock = new Object(); private ArrayList tasks = new ArrayList(); // one shot tasks - private Display display = null; private String name; - private long edtPollGranularity = 10; + private Runnable pumpMessages; + private long edtPollGranularity = 10; // 10ms, 1/100s - public EventDispatchThread(Display display, ThreadGroup tg, String name) { - this.display = display; + public EDTUtil(ThreadGroup tg, String name, Runnable pumpMessages) { this.threadGroup = tg; - this.name=new String("EDT-Display_"+display.getName()+"-"+name); + this.name=new String("EDT-"+name); + this.pumpMessages=pumpMessages; } public String getName() { return name; } public ThreadGroup getThreadGroup() { return threadGroup; } - public void start() { - start(false); + public Thread start() { + return start(false); } /** @@ -75,52 +75,56 @@ public class EventDispatchThread { * Usefull in combination with externalStimuli=true, * so an external stimuli can call it. */ - public Runnable start(boolean externalStimuli) { - synchronized(taskWorkerLock) { - if(null==taskWorker) { - taskWorker = new TaskWorker(threadGroup, name); + public Thread start(boolean externalStimuli) { + synchronized(edtLock) { + if(null==edt) { + edt = new EventDispatchThread(threadGroup, name); } - if(!taskWorker.isRunning()) { + if(!edt.isRunning()) { shouldStop = false; - taskWorker.start(externalStimuli); + edt.start(externalStimuli); } - taskWorkerLock.notifyAll(); + edtLock.notifyAll(); } - return taskWorker; + return edt; } public void stop() { - synchronized(taskWorkerLock) { - if(null!=taskWorker && taskWorker.isRunning()) { + synchronized(edtLock) { + if(null!=edt && edt.isRunning()) { shouldStop = true; } - taskWorkerLock.notifyAll(); + edtLock.notifyAll(); if(DEBUG) { System.out.println(Thread.currentThread()+": EDT signal STOP"); } } } + public Thread getEDT() { + return edt; + } + public boolean isThreadEDT(Thread thread) { - return null!=taskWorker && taskWorker == thread; + return null!=edt && edt == thread; } public boolean isCurrentThreadEDT() { - return null!=taskWorker && taskWorker == Thread.currentThread(); + return null!=edt && edt == Thread.currentThread(); } public boolean isRunning() { - return null!=taskWorker && taskWorker.isRunning() ; + return null!=edt && edt.isRunning() ; } public void invokeLater(Runnable task) { if(task == null) { return; } - synchronized(taskWorkerLock) { - if(null!=taskWorker && taskWorker.isRunning() && taskWorker != Thread.currentThread() ) { + synchronized(edtLock) { + if(null!=edt && edt.isRunning() && edt != Thread.currentThread() ) { tasks.add(task); - taskWorkerLock.notifyAll(); + edtLock.notifyAll(); } else { // if !running or isEDTThread, do it right away task.run(); @@ -137,10 +141,10 @@ public class EventDispatchThread { } public void waitOnWorker() { - synchronized(taskWorkerLock) { - if(null!=taskWorker && taskWorker.isRunning() && tasks.size()>0 && taskWorker != Thread.currentThread() ) { + synchronized(edtLock) { + if(null!=edt && edt.isRunning() && tasks.size()>0 && edt != Thread.currentThread() ) { try { - taskWorkerLock.wait(); + edtLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } @@ -149,10 +153,10 @@ public class EventDispatchThread { } public void waitUntilStopped() { - synchronized(taskWorkerLock) { - while(null!=taskWorker && taskWorker.isRunning() && taskWorker != Thread.currentThread() ) { + synchronized(edtLock) { + while(null!=edt && edt.isRunning() && edt != Thread.currentThread() ) { try { - taskWorkerLock.wait(); + edtLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } @@ -160,11 +164,11 @@ public class EventDispatchThread { } } - class TaskWorker extends Thread { + class EventDispatchThread extends Thread { boolean isRunning = false; boolean externalStimuli = false; - public TaskWorker(ThreadGroup tg, String name) { + public EventDispatchThread(ThreadGroup tg, String name) { super(tg, name); } @@ -183,7 +187,7 @@ public class EventDispatchThread { } /** - * Utilizing taskWorkerLock only for local resources and task execution, + * Utilizing edtLock only for local resources and task execution, * not for event dispatching. */ public void run() { @@ -194,26 +198,26 @@ public class EventDispatchThread { try { // wait for something todo while(!shouldStop && tasks.size()==0) { - synchronized(taskWorkerLock) { + synchronized(edtLock) { if(!shouldStop && tasks.size()==0) { try { - taskWorkerLock.wait(edtPollGranularity); + edtLock.wait(edtPollGranularity); } catch (InterruptedException e) { e.printStackTrace(); } } } - display.pumpMessages(); // event dispatch + pumpMessages.run(); // event dispatch } if(!shouldStop && tasks.size()>0) { - synchronized(taskWorkerLock) { + synchronized(edtLock) { if(!shouldStop && tasks.size()>0) { Runnable task = (Runnable) tasks.remove(0); task.run(); - taskWorkerLock.notifyAll(); + edtLock.notifyAll(); } } - display.pumpMessages(); // event dispatch + pumpMessages.run(); // event dispatch } } catch (Throwable t) { // handle errors .. @@ -227,8 +231,8 @@ public class EventDispatchThread { isRunning = !shouldStop; } if(!isRunning) { - synchronized(taskWorkerLock) { - taskWorkerLock.notifyAll(); + synchronized(edtLock) { + edtLock.notifyAll(); } } if(DEBUG) { diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 11f7d0f6c..0fccc94bb 100755 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -186,6 +186,57 @@ static void _throwNewRuntimeException(Display * unlockDisplay, JNIEnv *env, cons * Display */ + +static XErrorHandler origErrorHandler = NULL ; + +static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) +{ + fprintf(stderr, "Warning: NEWT X11 Error: DisplayDispatch %p, Code 0x%X\n", dpy, e->error_code); + + if (e->error_code == BadAtom) + { + fprintf(stderr, " BadAtom (%p): Atom probably already removed\n", e->resourceid); + } else if (e->error_code == BadWindow) + { + fprintf(stderr, " BadWindow (%p): Window probably already removed\n", e->resourceid); + } else { + return origErrorHandler(dpy, e); + } + + return 0; +} + +static void displayDispatchErrorHandlerEnable(int onoff) { + if(onoff) { + if(NULL==origErrorHandler) { + origErrorHandler = XSetErrorHandler(displayDispatchErrorHandler); + } + } else { + XSetErrorHandler(origErrorHandler); + origErrorHandler = NULL; + } +} + +static XIOErrorHandler origIOErrorHandler = NULL; + +static int displayDispatchIOErrorHandler(Display *dpy) +{ + fprintf(stderr, "Fatal: NEWT X11 IOError: Display %p not available\n", dpy); + return 0; +} + +static void displayDispatchIOErrorHandlerEnable(int onoff) { + if(onoff) { + if(NULL==origIOErrorHandler) { + origIOErrorHandler = XSetIOErrorHandler(displayDispatchIOErrorHandler); + } + } else { + XSetIOErrorHandler(origIOErrorHandler); + origIOErrorHandler = NULL; + } +} + + /* * Class: com_jogamp_newt_x11_X11Display * Method: initIDs @@ -197,7 +248,7 @@ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_x11_X11Display_initIDs jclass c; if( 0 == XInitThreads() ) { - fprintf(stderr, "Warning: XInitThreads() failed\n"); + fprintf(stderr, "Warning: NEWT X11Window: XInitThreads() failed\n"); } displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); @@ -249,6 +300,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_LockDisplay _throwNewRuntimeException(NULL, env, "given display connection is NULL\n"); } XLockDisplay(dpy) ; + DBG_PRINT1( "X11: LockDisplay 0x%X\n", dpy); } @@ -265,6 +317,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_UnlockDisplay _throwNewRuntimeException(NULL, env, "given display connection is NULL\n"); } XUnlockDisplay(dpy) ; + DBG_PRINT1( "X11: UnlockDisplay 0x%X\n", dpy); } @@ -356,14 +409,13 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j &nitems_return, &bytes_after_return, &jogl_java_object_data_pp); if ( Success != res ) { - _throwNewRuntimeException(dpy, env, "could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, bail out!\n", - res, nitems_return, bytes_after_return); + 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); - _throwNewRuntimeException(dpy, env, "could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, actual_type_return %ld, JOGL_JAVA_OBJECT %ld, bail out!\n", + 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; } @@ -374,7 +426,7 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j #ifdef VERBOSE_ON if(JNI_FALSE == (*env)->IsInstanceOf(env, jwindow, newtWindowClz)) { - _throwNewRuntimeException(NULL, env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !\n", jwindow); + _throwNewRuntimeException(dpy, env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !\n", jwindow); } #endif return jwindow; @@ -395,6 +447,8 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_DispatchMessages return; } + displayDispatchIOErrorHandlerEnable(1); + // Periodically take a break while( num_events > 0 ) { jobject jwindow = NULL; @@ -408,6 +462,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_DispatchMessages // num_events = XPending(dpy); // XEventsQueued(dpy, QueuedAfterFlush); // I/O Flush .. // num_events = XEventsQueued(dpy, QueuedAlready); // Better, no I/O .. if ( 0 >= XEventsQueued(dpy, QueuedAlready) ) { + displayDispatchIOErrorHandlerEnable(0); XUnlockDisplay(dpy) ; return; } @@ -415,6 +470,8 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_DispatchMessages XNextEvent(dpy, &evt); num_events--; + displayDispatchIOErrorHandlerEnable(0); + if( 0==evt.xany.window ) { _throwNewRuntimeException(dpy, env, "event window NULL, bail out!\n"); return ; @@ -424,10 +481,16 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_x11_X11Display_DispatchMessages _throwNewRuntimeException(dpy, env, "wrong display, bail out!\n"); return ; } + + displayDispatchErrorHandlerEnable(1); + jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom); + displayDispatchErrorHandlerEnable(0); + if(NULL==jwindow) { - // just leave .. _throwNewRuntimeException(env, "could not fetch Java Window object, bail out!\n"); + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for invalid X11 window %p\n", + dpy, evt.type, evt.xany.window); XUnlockDisplay(dpy) ; return; } |