diff options
author | Sven Gothel <[email protected]> | 2009-10-10 04:24:26 -0700 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2009-10-10 04:24:26 -0700 |
commit | 2268a6ce8a900ae7aa9f20d5f595f811185574a9 (patch) | |
tree | b4426ed20e1957bd5cba095d5a036df2bbc1736a | |
parent | 20c6d89bfc4f72144b8bcc48839da7ef9bc40681 (diff) |
NEWT: Add EventDispatchThread (EDT) pattern.
Due to limitations on Windows,
we need to standardize the one thread for
- window creation, and
- event dispatching
This was already mentioned in the previous implementation
but while integrating into another threading model (Plugin3),
it turned out that manual managing the thread is too much of a burden.
NEWT now uses a EDT per Display and Thread as the default,
where Display creation, Window creation and event dispatching is 'pipelined' into.
This can be switched off:
NewtFactory.setUseEDT(boolean onoff);
and queried via:
NewtFactory.useEDT();
Note this EDT impl. does not implicate a global lock or whatsoever.
The experimantal semantics of a current GL context
for input event dispatching is removed,
i.e. the GL context is no more made current for mouse/key listener.
This reduces the complexity and allows the proper impl. of
the external dispatch via EDT .. for example.
Removed:
GLWindow: setEventHandlerMode(int) .. etc
X11Display: XLockDisplay/XUnlockDisplay
needed to be utilized to allow the new
multithreading (EDT/Render) Display usage.
X11Window: lockSurface/unlockSurface
locks X11Display as well ..
+++++
NEWT: 'getSurfaceHandle()' semantics changed.
To allow usage of the surfaceHandle for OS
where it is allocated thread local (MS-Windows),
it shall be aquired/released while lockSurface/unlockSurface.
This is done in the Windows Window implementation.
GLWindow can no more query 'getSurfaceHandle()'
to verify if 'setRealized()' was successful.
NEWT: Window surface lock is recursive and blocking now,
as it shall be.
19 files changed, 723 insertions, 381 deletions
diff --git a/make/stub_includes/x11/window-lib.c b/make/stub_includes/x11/window-lib.c index bd03bdcbb..3096cde4c 100644 --- a/make/stub_includes/x11/window-lib.c +++ b/make/stub_includes/x11/window-lib.c @@ -13,6 +13,10 @@ extern Display *XOpenDisplay( extern int XCloseDisplay(Display *display); +extern void XLockDisplay(Display *display); + +extern void XUnlockDisplay(Display *display); + extern XVisualInfo *XGetVisualInfo( Display* /* display */, long /* vinfo_mask */, diff --git a/src/jogl/classes/com/sun/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/com/sun/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index add5c7b25..229042d9d 100644 --- a/src/jogl/classes/com/sun/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/com/sun/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -111,7 +111,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio long hdc = nativeWindow.getSurfaceHandle(); if (DEBUG) { - Exception ex = new Exception("WindowsWGLGraphicsConfigurationFactory got HDC 0x"+Long.toHexString(hdc)); + Exception ex = new Exception("WindowsWGLGraphicsConfigurationFactory got HDC "+toHexString(hdc)); ex.printStackTrace(); System.err.println("WindowsWGLGraphicsConfigurationFactory got NW "+nativeWindow); } @@ -128,7 +128,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio // - the graphics driver, copying the HDC's pixelformat to the new one, // - or the Java2D/OpenGL pipeline's configuration if (DEBUG) { - System.err.println("!!!! NOTE: pixel format already chosen for HDC: 0x" + Long.toHexString(hdc)+ + System.err.println("!!!! NOTE: pixel format already chosen for HDC: " + toHexString(hdc)+ ", pixelformat "+pixelFormat); } pixelFormatSet = true; @@ -149,6 +149,8 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio dummyContext.makeCurrent(); dummyWGLExt = (WGLExt) dummyContext.getPlatformGLExtensions(); } + } else if (DEBUG) { + System.err.println(getThreadName() + ": Not using WGL_ARB_pixel_format, because multisampling not requested"); } int recommendedPixelFormat = pixelFormat; // 1-based pixel format boolean haveWGLChoosePixelFormatARB = false; @@ -189,7 +191,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio } if (DEBUG) { if (recommendedPixelFormat <= 0) { - System.err.print(getThreadName() + ": wglChoosePixelFormatARB didn't recommend a pixel format"); + System.err.print(getThreadName() + ": wglChoosePixelFormatARB didn't recommend a pixel format: "+WGL.GetLastError()); if (capabilities.getSampleBuffers()) { System.err.print(" for multisampled GLCapabilities"); } @@ -202,6 +204,8 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio availableCaps = WindowsWGLGraphicsConfiguration.HDC2GLCapabilities(dummyWGLExt, hdc, -1, glProfile, pixelFormatSet, onscreen, usePBuffer); gotAvailableCaps = null!=availableCaps ; choosenBywGLPixelFormat = gotAvailableCaps ; + } else if (DEBUG) { + System.err.println(getThreadName() + ": wglChoosePixelFormatARB not available"); } } finally { dummyContext.release(); @@ -212,22 +216,19 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio if (!gotAvailableCaps) { if (DEBUG) { - if (!capabilities.getSampleBuffers()) { - System.err.println(getThreadName() + ": Using ChoosePixelFormat because multisampling not requested"); - } else { - System.err.println(getThreadName() + ": Using ChoosePixelFormat because no wglChoosePixelFormatARB"); - } + System.err.println(getThreadName() + ": Using ChoosePixelFormat ... (LastError: "+WGL.GetLastError()+")"); } pfd = WindowsWGLGraphicsConfiguration.GLCapabilities2PFD(capabilities); recommendedPixelFormat = WGL.ChoosePixelFormat(hdc, pfd); if (DEBUG) { - System.err.println(getThreadName() + ": Recommended pixel format = " + recommendedPixelFormat); + System.err.println(getThreadName() + ": ChoosePixelFormat(HDC "+toHexString(hdc)+") = " + recommendedPixelFormat + " (LastError: "+WGL.GetLastError()+")"); + System.err.println(getThreadName() + ": Used " + capabilities); } numFormats = WGL.DescribePixelFormat(hdc, 1, 0, null); if (numFormats == 0) { throw new GLException("Unable to enumerate pixel formats of window " + - toHexString(hdc) + " for GLCapabilitiesChooser"); + toHexString(hdc) + " for GLCapabilitiesChooser (LastError: "+WGL.GetLastError()+")"); } availableCaps = new GLCapabilities[numFormats]; for (int i = 0; i < numFormats; i++) { diff --git a/src/jogl/classes/com/sun/opengl/util/Animator.java b/src/jogl/classes/com/sun/opengl/util/Animator.java index 84637433e..a10717881 100755 --- a/src/jogl/classes/com/sun/opengl/util/Animator.java +++ b/src/jogl/classes/com/sun/opengl/util/Animator.java @@ -53,28 +53,46 @@ import javax.media.opengl.*; */ public class Animator { + protected static final boolean DEBUG = com.sun.opengl.impl.Debug.debug("Animator"); + private volatile ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList(); private AnimatorImpl impl; private Runnable runnable; private boolean runAsFastAsPossible; + protected ThreadGroup threadGroup; protected Thread thread; protected volatile boolean shouldStop; protected boolean ignoreExceptions; protected boolean printExceptions; /** Creates a new, empty Animator. */ - public Animator() { + public Animator(ThreadGroup tg) { try { // Try to use the AWT-capable Animator implementation by default impl = (AnimatorImpl) Class.forName("com.sun.opengl.util.awt.AWTAnimatorImpl").newInstance(); } catch (Exception e) { impl = new AnimatorImpl(); } + threadGroup = tg; + + if(DEBUG) { + System.out.println("Animator created, ThreadGroup: "+threadGroup); + } + } + + public Animator() { + this((ThreadGroup)null); } /** Creates a new Animator for a particular drawable. */ public Animator(GLAutoDrawable drawable) { - this(); + this((ThreadGroup)null); + add(drawable); + } + + /** Creates a new Animator for a particular drawable. */ + public Animator(ThreadGroup tg, GLAutoDrawable drawable) { + this(tg); add(drawable); } @@ -134,6 +152,9 @@ public class Animator { class MainLoop implements Runnable { public void run() { try { + if(DEBUG) { + System.out.println("Animator started: "+Thread.currentThread()); + } while (!shouldStop) { // Don't consume CPU unless there is work to be done if (drawables.size() == 0) { @@ -152,6 +173,9 @@ public class Animator { Thread.yield(); } } + if(DEBUG) { + System.out.println("Animator stopped: "+Thread.currentThread()); + } } finally { shouldStop = false; synchronized (Animator.this) { @@ -170,7 +194,11 @@ public class Animator { if (runnable == null) { runnable = new MainLoop(); } - thread = new Thread(runnable); + if(null==threadGroup) { + thread = new Thread(runnable); + } else { + thread = new Thread(threadGroup, runnable); + } thread.start(); } diff --git a/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java b/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java index e821f9b3a..b0548bb14 100644 --- a/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/com/sun/nativewindow/impl/jawt/JAWTWindow.java @@ -94,11 +94,13 @@ public abstract class JAWTWindow implements NativeWindow { private volatile Exception lockedStack = null; public synchronized int lockSurface() throws NativeWindowException { - // We have to be the owner of the JAWT ToolkitLock 'lock' to benefit from the - // recursive lock capabitlites. Otherwise a followup ToolkitLock would - // deadlock, since we already have locked JAWT with the surface lock. + // We have to be the owner of the JAWT ToolkitLock 'lock' to benefit from it's + // recursive and blocking lock capabitlites. + // Otherwise a followup ToolkitLock would deadlock, + // since we already have locked JAWT with the surface lock. NativeWindowFactory.getDefaultFactory().getToolkitLock().lock(); + // recursion not necessary here, due to the blocking ToolkitLock .. if (null!=lockedStack) { lockedStack.printStackTrace(); throw new NativeWindowException("JAWT Surface already locked - "+Thread.currentThread().getName()+" "+this); diff --git a/src/newt/classes/com/sun/javafx/newt/Display.java b/src/newt/classes/com/sun/javafx/newt/Display.java index 0be8aedbc..ad4664ac8 100755 --- a/src/newt/classes/com/sun/javafx/newt/Display.java +++ b/src/newt/classes/com/sun/javafx/newt/Display.java @@ -35,9 +35,10 @@ package com.sun.javafx.newt; import javax.media.nativewindow.*; import com.sun.javafx.newt.impl.Debug; +import com.sun.javafx.newt.util.EventDispatchThread; import java.util.*; -public abstract class Display implements Runnable { +public abstract class Display { public static final boolean DEBUG = Debug.debug("Display"); private static Class getDisplayClass(String type) @@ -62,6 +63,7 @@ public abstract class Display implements Runnable { return displayClass; } + // Unique Display for each thread private static ThreadLocal currentDisplayMap = new ThreadLocal(); /** Returns the thread local display map */ @@ -109,11 +111,11 @@ public abstract class Display implements Runnable { return display; } - private static void dumpDisplayMap(String prefix) { + public static void dumpDisplayMap(String prefix) { Map displayMap = getCurrentDisplayMap(); Set entrySet = displayMap.entrySet(); Iterator i = entrySet.iterator(); - System.err.println(prefix+" DisplayMap["+entrySet.size()+"] "+Thread.currentThread().getName()); + System.err.println(prefix+" DisplayMap["+entrySet.size()+"] "+Thread.currentThread()); for(int j=0; i.hasNext(); j++) { Map.Entry entry = (Map.Entry) i.next(); System.err.println(" ["+j+"] "+entry.getKey()+" -> "+entry.getValue()); @@ -128,58 +130,100 @@ public abstract class Display implements Runnable { /** Make sure to reuse a Display with the same name */ protected static Display create(String type, String name) { try { + if(DEBUG) { + dumpDisplayMap("Display.create("+name+") BEGIN"); + } Display display = getCurrentDisplay(name); if(null==display) { Class displayClass = getDisplayClass(type); display = (Display) displayClass.newInstance(); display.name=name; display.refCount=1; - display.createNative(); + + 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() { + public void run() { + f_dpy.createNative(); + } + } ); + } else { + display.createNative(); + } if(null==display.aDevice) { throw new RuntimeException("Display.createNative() failed to instanciate an AbstractGraphicsDevice"); } setCurrentDisplay(display); if(DEBUG) { - System.err.println("Display.create("+name+") NEW: "+display+" "+Thread.currentThread().getName()); + System.err.println("Display.create("+name+") NEW: "+display+" "+Thread.currentThread()); } } else { synchronized(display) { display.refCount++; if(DEBUG) { - System.err.println("Display.create("+name+") REUSE: refCount "+display.refCount+", "+display+" "+Thread.currentThread().getName()); + System.err.println("Display.create("+name+") REUSE: refCount "+display.refCount+", "+display+" "+Thread.currentThread()); } } } + if(DEBUG) { + dumpDisplayMap("Display.create("+name+") END"); + } + return display; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected static Display wrapHandle(String type, String name, AbstractGraphicsDevice aDevice) { + try { + Class displayClass = getDisplayClass(type); + Display display = (Display) displayClass.newInstance(); + display.name=name; + display.aDevice=aDevice; return display; } catch (Exception e) { throw new RuntimeException(e); } } + public EventDispatchThread getEDT() { return eventDispatchThread; } + public synchronized void destroy() { + if(DEBUG) { + dumpDisplayMap("Display.destroy("+name+") BEGIN"); + } refCount--; if(0==refCount) { removeCurrentDisplay(name); if(DEBUG) { - System.err.println("Display.destroy("+name+") REMOVE: "+this+" "+Thread.currentThread().getName()); + System.err.println("Display.destroy("+name+") REMOVE: "+this+" "+Thread.currentThread()); + } + if(null!=eventDispatchThread) { + final Display f_dpy = this; + eventDispatchThread.invokeAndWait(new Runnable() { + public void run() { + f_dpy.closeNative(); + } + } ); + } else { + closeNative(); + } + aDevice = null; + if(null!=eventDispatchThread) { + eventDispatchThread.stop(); + eventDispatchThread.waitUntilStopped(); + eventDispatchThread=null; } - closeNative(); } else { if(DEBUG) { - System.err.println("Display.destroy("+name+") KEEP: refCount "+refCount+", "+this+" "+Thread.currentThread().getName()); + System.err.println("Display.destroy("+name+") KEEP: refCount "+refCount+", "+this+" "+Thread.currentThread()); } } - } - - protected static Display wrapHandle(String type, String name, AbstractGraphicsDevice aDevice) { - try { - Class displayClass = getDisplayClass(type); - Display display = (Display) displayClass.newInstance(); - display.name=name; - display.aDevice=aDevice; - return display; - } catch (Exception e) { - throw new RuntimeException(e); + if(DEBUG) { + dumpDisplayMap("Display.destroy("+name+") END"); } } @@ -191,32 +235,23 @@ public abstract class Display implements Runnable { } public long getHandle() { - return aDevice.getHandle(); + if(null!=aDevice) { + return aDevice.getHandle(); + } + return 0; } public AbstractGraphicsDevice getGraphicsDevice() { return aDevice; } - public synchronized void pumpMessages() { - dispatchMessages(); - } - - /** calls {@link #pumpMessages} */ - public void run() { - pumpMessages(); - } - - public static interface Action { - public void run(Display display); - } - - /** Calls {@link Display.Action#run(Display)} on all Display's - bound to the current thread. */ - public static void runCurrentThreadDisplaysAction(Display.Action action) { - Iterator iter = getCurrentDisplays().iterator(); // Thread local .. no sync necessary - while(iter.hasNext()) { - action.run((Display) iter.next()); + public void pumpMessages() { + if(null!=eventDispatchThread) { + dispatchMessages(); + } else { + synchronized(this) { + dispatchMessages(); + } } } @@ -226,6 +261,7 @@ public abstract class Display implements Runnable { protected abstract void dispatchMessages(); + protected EventDispatchThread eventDispatchThread = null; protected String name; protected int refCount; protected AbstractGraphicsDevice aDevice; diff --git a/src/newt/classes/com/sun/javafx/newt/DisplayActionThread.java b/src/newt/classes/com/sun/javafx/newt/DisplayActionThread.java deleted file mode 100644 index 8f02148a2..000000000 --- a/src/newt/classes/com/sun/javafx/newt/DisplayActionThread.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - */ -package com.sun.javafx.newt; - -import javax.media.nativewindow.*; -import com.sun.javafx.newt.impl.Debug; -import java.util.*; - -public class DisplayActionThread extends Thread { - private Object taskWorkerLock=new Object(); - private boolean isRunning = false; - private boolean shouldStop = false; - private List/*DisplayAction*/ displayActions = new ArrayList(); - - public synchronized void addAction(Display.Action da) { - List newListeners = (List) ((ArrayList) displayActions).clone(); - newListeners.add(da); - displayActions = newListeners; - } - - public synchronized void removeAction(Display.Action da) { - List newListeners = (List) ((ArrayList) displayActions).clone(); - newListeners.remove(da); - displayActions = newListeners; - } - - public boolean isRunning() { - synchronized(taskWorkerLock) { - return isRunning; - } - } - - public void exit() { - synchronized(taskWorkerLock) { - if(isRunning) { - shouldStop = true; - taskWorkerLock.notifyAll(); - } - } - Map displayMap = Display.getCurrentDisplayMap(); - synchronized(displayMap) { - displayMap.notifyAll(); - } - } - - public void start() { - synchronized(taskWorkerLock) { - if(!isRunning) { - shouldStop = false; - taskWorkerLock.notifyAll(); - super.start(); - } - } - } - - public void run() { - synchronized(taskWorkerLock) { - isRunning = true; - taskWorkerLock.notifyAll(); - } - while(!shouldStop) { - Map displayMap = Display.getCurrentDisplayMap(); - // wait for something todo .. - synchronized(displayMap) { - while(!shouldStop && displayMap.size()==0) { - try { - displayMap.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - Iterator iter = Display.getCurrentDisplays().iterator(); - while(iter.hasNext()) { - Display display = (Display) iter.next(); - Iterator iterDA = displayActions.iterator(); - while(iterDA.hasNext()) { - ((Display.Action)iterDA.next()).run(display); - } - } - } - synchronized(taskWorkerLock) { - isRunning = false; - taskWorkerLock.notifyAll(); - } - } -} diff --git a/src/newt/classes/com/sun/javafx/newt/Event.java b/src/newt/classes/com/sun/javafx/newt/Event.java index 7d2b24ba5..3c045c52b 100644 --- a/src/newt/classes/com/sun/javafx/newt/Event.java +++ b/src/newt/classes/com/sun/javafx/newt/Event.java @@ -74,4 +74,13 @@ public class Event { public String toString() { return "Event[sys:"+isSystemEvent()+", source:"+getSource()+", when:"+getWhen()+"]"; } + + public static String toHexString(int hex) { + return "0x" + Integer.toHexString(hex); + } + + public static String toHexString(long hex) { + return "0x" + Long.toHexString(hex); + } + } diff --git a/src/newt/classes/com/sun/javafx/newt/KeyEvent.java b/src/newt/classes/com/sun/javafx/newt/KeyEvent.java index 7e224dbad..c7450da67 100644 --- a/src/newt/classes/com/sun/javafx/newt/KeyEvent.java +++ b/src/newt/classes/com/sun/javafx/newt/KeyEvent.java @@ -53,7 +53,7 @@ public class KeyEvent extends InputEvent public String toString() { return "KeyEvent["+getEventTypeString(getEventType())+ - ", code "+keyCode+"(0x"+Integer.toHexString(keyCode)+"), char <"+keyChar+"> (0x"+Integer.toHexString((int)keyChar)+"), isActionKey "+isActionKey()+", "+super.toString()+"]"; + ", code "+keyCode+"("+toHexString(keyCode)+"), char <"+keyChar+"> ("+toHexString((int)keyChar)+"), isActionKey "+isActionKey()+", "+super.toString()+"]"; } public static String getEventTypeString(int type) { diff --git a/src/newt/classes/com/sun/javafx/newt/NewtFactory.java b/src/newt/classes/com/sun/javafx/newt/NewtFactory.java index c4180eb46..6e25b19eb 100755 --- a/src/newt/classes/com/sun/javafx/newt/NewtFactory.java +++ b/src/newt/classes/com/sun/javafx/newt/NewtFactory.java @@ -57,6 +57,20 @@ public abstract class NewtFactory { return clazz; } + private static boolean useEDT = true; + + /** + * Toggles the usage of an EventDispatchThread while creating a Display.<br> + * The default is enabled.<br> + * The EventDispatchThread is thread local to the Display instance.<br> + */ + public static synchronized void setUseEDT(boolean onoff) { + useEDT = onoff; + } + + /** @see #setUseEDT(boolean) */ + public static boolean useEDT() { return useEDT; } + /** * Create a Display entity, incl native creation */ diff --git a/src/newt/classes/com/sun/javafx/newt/Screen.java b/src/newt/classes/com/sun/javafx/newt/Screen.java index e347a69c2..9edd0b719 100755 --- a/src/newt/classes/com/sun/javafx/newt/Screen.java +++ b/src/newt/classes/com/sun/javafx/newt/Screen.java @@ -84,6 +84,8 @@ public abstract class Screen { public synchronized void destroy() { closeNative(); + display = null; + aScreen = null; } protected static Screen wrapHandle(String type, Display display, AbstractGraphicsScreen aScreen) { diff --git a/src/newt/classes/com/sun/javafx/newt/Window.java b/src/newt/classes/com/sun/javafx/newt/Window.java index 85b8723f9..7bebe2125 100755 --- a/src/newt/classes/com/sun/javafx/newt/Window.java +++ b/src/newt/classes/com/sun/javafx/newt/Window.java @@ -34,6 +34,7 @@ package com.sun.javafx.newt; import com.sun.javafx.newt.impl.Debug; +import com.sun.javafx.newt.util.EventDispatchThread; import javax.media.nativewindow.*; import com.sun.nativewindow.impl.NWReflection; @@ -85,7 +86,7 @@ public abstract class Window implements NativeWindow return windowClass; } - protected static Window create(String type, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { + protected static Window create(String type, final long parentWindowHandle, Screen screen, final Capabilities caps, boolean undecorated) { try { Class windowClass; if(caps.isOnscreen()) { @@ -97,7 +98,17 @@ public abstract class Window implements NativeWindow window.invalidate(); window.screen = screen; window.setUndecorated(undecorated||0!=parentWindowHandle); - window.createNative(parentWindowHandle, caps); + EventDispatchThread edt = screen.getDisplay().getEDT(); + if(null!=edt) { + final Window f_win = window; + edt.invokeAndWait(new Runnable() { + public void run() { + f_win.createNative(parentWindowHandle, caps); + } + } ); + } else { + window.createNative(parentWindowHandle, caps); + } return window; } catch (Throwable t) { t.printStackTrace(); @@ -105,7 +116,7 @@ public abstract class Window implements NativeWindow } } - protected static Window create(String type, Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { + protected static Window create(String type, Object[] cstrArguments, Screen screen, final Capabilities caps, boolean undecorated) { try { Class windowClass = getWindowClass(type); Class[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass); @@ -120,7 +131,17 @@ public abstract class Window implements NativeWindow window.invalidate(); window.screen = screen; window.setUndecorated(undecorated); - window.createNative(0, caps); + EventDispatchThread edt = screen.getDisplay().getEDT(); + if(null!=edt) { + final Window f_win = window; + edt.invokeAndWait(new Runnable() { + public void run() { + f_win.createNative(0, caps); + } + } ); + } else { + window.createNative(0, caps); + } return window; } catch (Throwable t) { t.printStackTrace(); @@ -152,6 +173,25 @@ public abstract class Window implements NativeWindow } } + public static String toHexString(int hex) { + return "0x" + Integer.toHexString(hex); + } + + public static String toHexString(long hex) { + return "0x" + Long.toHexString(hex); + } + + protected Screen screen; + + protected AbstractGraphicsConfiguration config; + protected long windowHandle; + protected boolean fullscreen, visible; + protected int width, height, x, y; + protected int eventMask; + + protected String title = "Newt Window"; + protected boolean undecorated = false; + /** * Create native windowHandle, ie creates a new native invisible window. * @@ -173,8 +213,8 @@ public abstract class Window implements NativeWindow StringBuffer sb = new StringBuffer(); sb.append(getClass().getName()+"[config "+config+ - ", windowHandle 0x"+Long.toHexString(getWindowHandle())+ - ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ + ", windowHandle "+toHexString(getWindowHandle())+ + ", surfaceHandle "+toHexString(getSurfaceHandle())+ ", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ ", visible "+isVisible()+ ", undecorated "+undecorated+ @@ -202,18 +242,6 @@ public abstract class Window implements NativeWindow return sb.toString(); } - protected Screen screen; - - protected AbstractGraphicsConfiguration config; - protected long windowHandle; - protected Exception lockedStack = null; - protected boolean fullscreen, visible; - protected int width, height, x, y; - protected int eventMask; - - protected String title = "Newt Window"; - protected boolean undecorated = false; - public String getTitle() { return title; } @@ -236,31 +264,55 @@ public abstract class Window implements NativeWindow // // NativeWindow impl // + private Thread owner; + private int recursionCount; + protected Exception lockedStack = null; - public synchronized int lockSurface() throws NativeWindowException { + /** Recursive and blocking lockSurface() implementation */ + public synchronized int lockSurface() { // We leave the ToolkitLock lock to the specializtion's discretion, // ie the implicit JAWTWindow in case of AWTWindow - if (null!=lockedStack) { - lockedStack.printStackTrace(); - throw new NativeWindowException("NEWT Surface already locked - "+Thread.currentThread().getName()+" "+this); + Thread cur = Thread.currentThread(); + if (owner == cur) { + ++recursionCount; + return LOCK_SUCCESS; } - - lockedStack = new Exception("NEWT Surface previously locked by "+Thread.currentThread().getName()); + while (owner != null) { + try { + wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + owner = cur; + lockedStack = new Exception("NEWT Surface previously locked by "+Thread.currentThread()); return LOCK_SUCCESS; } - public synchronized void unlockSurface() { - if (null!=lockedStack) { - lockedStack = null; - } else { - throw new NativeWindowException("NEWT Surface not locked"); + /** Recursive and unblocking unlockSurface() implementation */ + public synchronized void unlockSurface() throws NativeWindowException { + Thread cur = Thread.currentThread(); + if (owner != cur) { + lockedStack.printStackTrace(); + throw new NativeWindowException(cur+": Not owner, owner is "+owner); } + if (recursionCount > 0) { + --recursionCount; + return; + } + owner = null; + lockedStack = null; + notifyAll(); // We leave the ToolkitLock unlock to the specializtion's discretion, // ie the implicit JAWTWindow in case of AWTWindow } public synchronized boolean isSurfaceLocked() { - return null!=lockedStack; + return null!=owner; + } + + public synchronized Thread getSurfaceLockOwner() { + return owner; } public synchronized Exception getLockedStack() { @@ -268,8 +320,13 @@ public abstract class Window implements NativeWindow } public synchronized void destroy() { + destroy(false); + } + + /** @param deep If true, the linked Screen and Display will be destroyed as well. */ + public synchronized void destroy(boolean deep) { if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.destroy() start "+Thread.currentThread().getName()); + System.out.println("Window.destroy() start (deep "+deep+" - "+Thread.currentThread()); } synchronized(surfaceUpdatedListeners) { surfaceUpdatedListeners = new ArrayList(); @@ -283,16 +340,32 @@ public abstract class Window implements NativeWindow synchronized(keyListeners) { keyListeners = new ArrayList(); } - closeNative(); + Screen scr = screen; + Display dpy = screen.getDisplay(); + EventDispatchThread edt = dpy.getEDT(); + if(null!=edt) { + final Window f_win = this; + edt.invokeAndWait(new Runnable() { + public void run() { + f_win.closeNative(); + } + } ); + } else { + closeNative(); + } invalidate(); + if(deep) { + scr.destroy(); + dpy.destroy(); + } if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.destroy() end "+Thread.currentThread().getName()); + System.out.println("Window.destroy() end "+Thread.currentThread()); } } public void invalidate() { if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - Exception e = new Exception("!!! Window Invalidate "+Thread.currentThread().getName()); + Exception e = new Exception("!!! Window Invalidate "+Thread.currentThread()); e.printStackTrace(); } screen = null; @@ -415,7 +488,7 @@ public abstract class Window implements NativeWindow protected void windowDestroyNotify() { if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.windowDestroyeNotify start "+Thread.currentThread().getName()); + System.out.println("Window.windowDestroyeNotify start "+Thread.currentThread()); } sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); @@ -425,13 +498,13 @@ public abstract class Window implements NativeWindow } if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.windowDestroyeNotify end "+Thread.currentThread().getName()); + System.out.println("Window.windowDestroyeNotify end "+Thread.currentThread()); } } protected void windowDestroyed() { if(DEBUG_WINDOW_EVENT) { - System.out.println("Window.windowDestroyed "+Thread.currentThread().getName()); + System.out.println("Window.windowDestroyed "+Thread.currentThread()); } invalidate(); } diff --git a/src/newt/classes/com/sun/javafx/newt/opengl/GLWindow.java b/src/newt/classes/com/sun/javafx/newt/opengl/GLWindow.java index 52f368148..aebf8f9dd 100644 --- a/src/newt/classes/com/sun/javafx/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/sun/javafx/newt/opengl/GLWindow.java @@ -41,45 +41,22 @@ import java.util.*; /** * An implementation of {@link Window} which is customized for OpenGL - * use, and which implements the {@link - * javax.media.opengl.GLAutoDrawable} interface. For convenience, this - * window class guarantees that its OpenGL context is current inside - * the various EventListeners' callbacks (MouseListener, KeyListener, - * etc.).<P> - * - * Best performance is currently achieved with default settings, - * {@link #setEventHandlerMode} to {@link #EVENT_HANDLER_GL_NONE} - * and one thread per GLWindow. To ensure compatibility with the - * underlying platform, window shall also be created within your - * working thread. See comment at {@link #setRunPumpMessages}. + * use, and which implements the {@link javax.media.opengl.GLAutoDrawable} interface. + * <P> + * This implementation does not make the OpenGL context current<br> + * before calling the various input EventListener callbacks (MouseListener, KeyListener, + * etc.).<br> + * This design decision is made to favor a more performant and simplified + * implementation, as well as the event dispatcher shall be allowed + * not having a notion about OpenGL. + * <p> */ public class GLWindow extends Window implements GLAutoDrawable { - /** - * Event handling mode: EVENT_HANDLER_GL_NONE. - * No GL context is current, while calling the EventListener. - * This might be inconvenient, but don't impact the performance. - * Also - * - * @see com.sun.javafx.newt.GLWindow#setEventHandlerMode(int) - */ - public static final int EVENT_HANDLER_GL_NONE = 0; - - /** - * Event handling mode: EVENT_HANDLER_GL_CURRENT. - * The GL context is made current, while calling the EventListener. - * This might be convenient, but impacts the performance - * due to context switches. - * - * This is the default setting! - * - * @see com.sun.javafx.newt.GLWindow#setEventHandlerMode(int) - */ - public static final int EVENT_HANDLER_GL_CURRENT = (1 << 0); - private static List/*GLWindow*/ glwindows = new ArrayList(); + private boolean ownerOfDisplayAndScreen; private Window window; - private boolean runPumpMessages = true; + private boolean runPumpMessages; /** Constructor. Do not call this directly -- use {@link create()} instead. */ @@ -87,6 +64,7 @@ public class GLWindow extends Window implements GLAutoDrawable { this.ownerOfDisplayAndScreen = ownerOfDisplayAndScreen; this.window = window; this.window.setAutoDrawableClient(true); + this.runPumpMessages = ( null == getScreen().getDisplay().getEDT() ) ; window.addWindowListener(new WindowListener() { public void windowResized(WindowEvent e) { sendReshape = true; @@ -166,9 +144,16 @@ public class GLWindow extends Window implements GLAutoDrawable { * * Best performance has been achieved with one GLWindow per thread.<br> * + * Enabling local pump messages while using the EDT, + * {@link com.sun.javafx.newt.NewtFactory#setUseEDT(boolean)}, + * will result in an exception. + * * @deprecated EXPERIMENTAL, semantic is about to be removed after further verification. */ public void setRunPumpMessages(boolean onoff) { + if( onoff && null!=getScreen().getDisplay().getEDT() ) { + throw new GLException("GLWindow.setRunPumpMessages(true) - Can't do with EDT on"); + } runPumpMessages = onoff; } @@ -182,7 +167,7 @@ public class GLWindow extends Window implements GLAutoDrawable { protected void dispose(boolean regenerate) { if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - Exception e1 = new Exception("GLWindow.dispose("+regenerate+") "+Thread.currentThread().getName()+", 1: "+this); + Exception e1 = new Exception("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", 1: "+this); e1.printStackTrace(); } @@ -213,21 +198,22 @@ public class GLWindow extends Window implements GLAutoDrawable { } drawable = factory.createGLDrawable(nw); drawable.setRealized(true); - if(getSurfaceHandle()==0) { - throw new GLException("SurfaceHandle==NULL after setRealize(true) "+this); - } context = drawable.createContext(null); sendReshape = true; // ensure a reshape event is send .. } if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - System.out.println("GLWindow.dispose("+regenerate+") "+Thread.currentThread().getName()+", fin: "+this); + System.out.println("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", fin: "+this); } } public synchronized void destroy() { + destroy(false); + } + + public synchronized void destroy(boolean deep) { if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - Exception e1 = new Exception("GLWindow.destroy "+Thread.currentThread().getName()+", 1: "+this); + Exception e1 = new Exception("GLWindow.destroy "+Thread.currentThread()+", 1: "+this); e1.printStackTrace(); } @@ -240,17 +226,17 @@ public class GLWindow extends Window implements GLAutoDrawable { Screen _screen = null; Display _device = null; if(null!=window) { - if(ownerOfDisplayAndScreen) { + if(!deep && ownerOfDisplayAndScreen) { _screen = getScreen(); if(null != _screen) { _device = _screen.getDisplay(); } } - window.destroy(); + window.destroy(deep); } if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - System.out.println("GLWindow.destroy "+Thread.currentThread().getName()+", fin: "+this); + System.out.println("GLWindow.destroy "+Thread.currentThread()+", fin: "+this); } drawable = null; @@ -271,21 +257,11 @@ public class GLWindow extends Window implements GLAutoDrawable { perfLog = v; } - /** - * Sets the event handling mode. - * - * @see com.sun.javafx.newt.GLWindow#EVENT_HANDLER_GL_NONE - * @see com.sun.javafx.newt.GLWindow#EVENT_HANDLER_GL_CURRENT - */ - public void setEventHandlerMode(int mode) { - eventHandlerMode = mode; - } - - public int getEventHandlerMode() { - return eventHandlerMode; - } - public void setVisible(boolean visible) { + if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { + System.out.println(Thread.currentThread()+" GLWindow.setVisible("+visible+") START ; isVisible "+this.visible+" ; has context "+(null!=context)); + } + this.visible=visible; window.setVisible(visible); if (visible && context == null) { NativeWindow nw; @@ -298,12 +274,12 @@ public class GLWindow extends Window implements GLAutoDrawable { factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); drawable = factory.createGLDrawable(nw); drawable.setRealized(true); - if(getSurfaceHandle()==0) { - throw new GLException("SurfaceHandle==NULL after setRealize(true) "+this); - } context = drawable.createContext(null); sendReshape = true; // ensure a reshape event is send .. } + if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { + System.out.println(Thread.currentThread()+" GLWindow.setVisible("+visible+") END ; has context "+(null!=context)); + } } public Screen getScreen() { @@ -423,8 +399,6 @@ public class GLWindow extends Window implements GLAutoDrawable { // OpenGL-related methods and state // - private static int eventHandlerMode = EVENT_HANDLER_GL_CURRENT; - private static boolean autoSwapBufferMode = true; private GLDrawableFactory factory; private GLDrawable drawable; private GLContext context; @@ -469,72 +443,14 @@ public class GLWindow extends Window implements GLAutoDrawable { helper.removeGLEventListener(listener); } - class DisplayPumpMessage implements Display.Action { - public void run(Display display) { - if( 0 == (eventHandlerMode & EVENT_HANDLER_GL_CURRENT) ) { - display.run(); - } else { - helper.setAutoSwapBufferMode(false); - try { - helper.invokeGL(drawable, context, display, initAction); - } finally { - helper.setAutoSwapBufferMode(autoSwapBufferMode); - } - } - } - } - private DisplayPumpMessage displayPumpMessage = new DisplayPumpMessage(); - - static class DisplayPumpMessageStatic implements Display.Action { - public void run(Display display) { - display.run(); - } - } - private static DisplayPumpMessageStatic displayPumpMessageStatic = new DisplayPumpMessageStatic(); - - /** - * @see #setRunPumpMessages - * @deprecated EXPERIMENTAL, semantic is about to be removed after further verification. - */ - public static void runCurrentThreadPumpMessage() { - Exception safedE = null; - - if( 0 != (eventHandlerMode & EVENT_HANDLER_GL_CURRENT) ) { - // for all: setup / init / makeCurrent - for(Iterator i = glwindows.iterator(); i.hasNext(); ) { - GLWindow glw = (GLWindow) i.next(); - glw.helper.setAutoSwapBufferMode(false); - glw.helper.invokeGL(glw.drawable, glw.context, null, glw.initAction); - } - } - - try { - Display.runCurrentThreadDisplaysAction(displayPumpMessageStatic); - } catch (Exception e) { - safedE=e; - } - - if( 0 != (eventHandlerMode & EVENT_HANDLER_GL_CURRENT) ) { - // for all: reset - for(Iterator i = glwindows.iterator(); i.hasNext(); ) { - GLWindow glw = (GLWindow) i.next(); - glw.helper.setAutoSwapBufferMode(autoSwapBufferMode); - } - } - - if(null!=safedE) { - throw new GLException(safedE); - } - } - public void display() { display(false); } public void display(boolean forceReshape) { - if(getSurfaceHandle()!=0) { + if(window!=null && drawable!=null && context != null) { if(runPumpMessages) { - displayPumpMessage.run(window.getScreen().getDisplay()); + window.getScreen().getDisplay().pumpMessages(); } if(window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) { dispose(true); @@ -552,24 +468,24 @@ public class GLWindow extends Window implements GLAutoDrawable { } private void sendDisposeEvent() { - if(disposeAction!=null && drawable!=null && context != null && window!=null && getSurfaceHandle()!=0) { + if(drawable!=null && context != null) { helper.invokeGL(drawable, context, disposeAction, null); } } /** This implementation uses a static value */ public void setAutoSwapBufferMode(boolean onOrOff) { - autoSwapBufferMode = onOrOff; + helper.setAutoSwapBufferMode(onOrOff); } /** This implementation uses a static value */ public boolean getAutoSwapBufferMode() { - return autoSwapBufferMode; + return helper.getAutoSwapBufferMode(); } public void swapBuffers() { - if(getSurfaceHandle()!=0) { - if (context != null && context != GLContext.getCurrent()) { + if(drawable!=null && context != null) { + if (context != GLContext.getCurrent()) { // Assume we should try to make the context current before swapping the buffers helper.invokeGL(drawable, context, swapBuffersAction, initAction); } else { @@ -638,7 +554,6 @@ public class GLWindow extends Window implements GLAutoDrawable { private long curTime = 0; private long lastCheck = 0; private int totalFrames = 0, lastFrames = 0; - private boolean ownerOfDisplayAndScreen; class SwapBuffersAction implements Runnable { public void run() { diff --git a/src/newt/classes/com/sun/javafx/newt/opengl/broadcom/egl/Window.java b/src/newt/classes/com/sun/javafx/newt/opengl/broadcom/egl/Window.java index 7d087416c..11672dde3 100755 --- a/src/newt/classes/com/sun/javafx/newt/opengl/broadcom/egl/Window.java +++ b/src/newt/classes/com/sun/javafx/newt/opengl/broadcom/egl/Window.java @@ -148,7 +148,7 @@ public class Window extends com.sun.javafx.newt.Window { throw new NativeWindowException("Error creating EGLGraphicsConfiguration from id: "+cfgID+", "+this); } if(DEBUG_IMPLEMENTATION) { - System.out.println("BCEGL Window.windowCreated(): 0x"+Integer.toHexString(cfgID)+", "+width+"x"+height+", "+config); + System.out.println("BCEGL Window.windowCreated(): "+toHexString(cfgID)+", "+width+"x"+height+", "+config); } } diff --git a/src/newt/classes/com/sun/javafx/newt/util/EventDispatchThread.java b/src/newt/classes/com/sun/javafx/newt/util/EventDispatchThread.java new file mode 100644 index 000000000..f8b205a8b --- /dev/null +++ b/src/newt/classes/com/sun/javafx/newt/util/EventDispatchThread.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +package com.sun.javafx.newt.util; + +import com.sun.javafx.newt.Display; +import java.util.*; + +public class EventDispatchThread { + private ThreadGroup threadGroup; + private volatile boolean shouldStop = false; + private TaskWorker taskWorker = null; + private Object taskWorkerLock = new Object(); + private ArrayList tasks = new ArrayList(); // one shot tasks + private Display display = null; + private String name; + private long edtPollGranularity = 10; + + public EventDispatchThread(Display display, ThreadGroup tg, String name) { + this.display = display; + this.threadGroup = tg; + this.name=new String("EDT-"+name); + } + + public String getName() { return name; } + + public ThreadGroup getThreadGroup() { return threadGroup; } + + public void start() { + start(false); + } + + /** + * @param externalStimuli true indicates that another thread stimulates, + * ie. calls this TaskManager's run() loop method. + * Hence no own thread is started in this case. + * + * @return The started Runnable, which handles the run-loop. + * 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); + } + if(!taskWorker.isRunning()) { + shouldStop = false; + taskWorker.start(externalStimuli); + } + taskWorkerLock.notifyAll(); + } + return taskWorker; + } + + public void stop() { + synchronized(taskWorkerLock) { + if(null!=taskWorker && taskWorker.isRunning()) { + shouldStop = true; + } + taskWorkerLock.notifyAll(); + } + } + + public boolean isEDTThread(Thread thread) { + return taskWorker == thread; + } + + public boolean isRunning() { + return null!=taskWorker && taskWorker.isRunning() ; + } + + public void invokeLater(Runnable task) { + if(task == null) { + return; + } + synchronized(taskWorkerLock) { + tasks.add(task); + taskWorkerLock.notifyAll(); + } + } + + public void invokeAndWait(Runnable task) { + if(task == null) { + return; + } + invokeLater(task); + waitOnWorker(); + } + + public void waitOnWorker() { + synchronized(taskWorkerLock) { + if(null!=taskWorker && taskWorker.isRunning() && tasks.size()>0 && taskWorker != Thread.currentThread() ) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public void waitUntilStopped() { + synchronized(taskWorkerLock) { + while(null!=taskWorker && taskWorker.isRunning() && taskWorker != Thread.currentThread() ) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + class TaskWorker extends Thread { + boolean isRunning = false; + boolean externalStimuli = false; + + public TaskWorker(ThreadGroup tg, String name) { + super(tg, name); + } + + public synchronized boolean isRunning() { + return isRunning; + } + + public void start(boolean externalStimuli) throws IllegalThreadStateException { + synchronized(this) { + this.externalStimuli = externalStimuli; + isRunning = true; + } + if(!externalStimuli) { + super.start(); + } + } + + public void run() { + while(!shouldStop) { + try { + // wait for something todo .. + synchronized(taskWorkerLock) { + while(!shouldStop && tasks.size()==0) { + try { + display.pumpMessages(); // event dispatch + taskWorkerLock.wait(edtPollGranularity); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if(tasks.size()>0) { + Runnable task = (Runnable) tasks.remove(0); + task.run(); + taskWorkerLock.notifyAll(); + } + } + display.pumpMessages(); // event dispatch + } catch (Throwable t) { + // handle errors .. + t.printStackTrace(); + } finally { + // epilog - unlock locked stuff + } + if(externalStimuli) break; // no loop if called by external stimuli + } + synchronized(this) { + isRunning = !shouldStop; + } + if(!isRunning) { + synchronized(taskWorkerLock) { + taskWorkerLock.notifyAll(); + } + } + } + } +} + diff --git a/src/newt/classes/com/sun/javafx/newt/windows/WindowsWindow.java b/src/newt/classes/com/sun/javafx/newt/windows/WindowsWindow.java index d044d61b5..5749039aa 100755 --- a/src/newt/classes/com/sun/javafx/newt/windows/WindowsWindow.java +++ b/src/newt/classes/com/sun/javafx/newt/windows/WindowsWindow.java @@ -53,16 +53,40 @@ public class WindowsWindow extends Window { public WindowsWindow() { } - public long getSurfaceHandle() { - if (hdc == 0 && 0!=windowHandle) { + Thread hdcOwner = null; + + public synchronized int lockSurface() throws NativeWindowException { + int res = super.lockSurface(); + if(LOCK_SUCCESS==res && 0!=windowHandle) { + if(hdc!=0) { + throw new NativeWindowException("NEWT Surface handle set HDC "+toHexString(hdc)+" - "+Thread.currentThread().getName()+" ; "+this); + } hdc = GetDC(windowHandle); hmon = MonitorFromWindow(windowHandle); - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - Exception e = new Exception("!!! Window new surface handle "+Thread.currentThread().getName()+ - ", HWND 0x"+Long.toHexString(windowHandle)+", HDC 0x"+Long.toHexString(hdc)+", HMON 0x"+Long.toHexString(hmon)); - e.printStackTrace(); + hdcOwner = Thread.currentThread(); + } + return res; + } + + public synchronized void unlockSurface() { + // prevalidate, before we change data .. + Thread cur = Thread.currentThread(); + if ( getSurfaceLockOwner() != cur ) { + getLockedStack().printStackTrace(); + throw new NativeWindowException(cur+": Not owner, owner is "+getSurfaceLockOwner()); + } + if (0!=hdc && 0!=windowHandle) { + if(hdcOwner != cur) { + throw new NativeWindowException("NEWT Surface handle set HDC "+toHexString(hdc)+" by other thread "+hdcOwner+", this "+cur+" ; "+this); } + ReleaseDC(windowHandle, hdc); + hdc=0; + hdcOwner=null; } + super.unlockSurface(); + } + + public long getSurfaceHandle() { return hdc; } @@ -72,7 +96,7 @@ public class WindowsWindow extends Window { if (hmon != _hmon) { if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { Exception e = new Exception("!!! Window Device Changed "+Thread.currentThread().getName()+ - ", HMON 0x"+Long.toHexString(hmon)+" -> 0x"+Long.toHexString(_hmon)); + ", HMON "+toHexString(hmon)+" -> "+toHexString(_hmon)); e.printStackTrace(); } hmon = _hmon; @@ -87,7 +111,7 @@ public class WindowsWindow extends Window { ReleaseDC(windowHandle, hdc); hdc=0; if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - Exception e = new Exception("!!! Window surface handle disposed "+Thread.currentThread().getName()); + Exception e = new Exception("!!! Window surface handle disposed "+Thread.currentThread().getName()+", "+Thread.currentThread()); e.printStackTrace(); } } @@ -110,7 +134,8 @@ public class WindowsWindow extends Window { windowHandleClose = windowHandle; if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { Exception e = new Exception("!!! Window new window handle "+Thread.currentThread().getName()+ - ", HWND 0x"+Long.toHexString(windowHandle)); + " (Parent HWND "+toHexString(parentWindowHandle)+ + ") : HWND "+toHexString(windowHandle)+", "+Thread.currentThread()); e.printStackTrace(); } } diff --git a/src/newt/classes/com/sun/javafx/newt/x11/X11Display.java b/src/newt/classes/com/sun/javafx/newt/x11/X11Display.java index 5a2e0ad5d..297f98edb 100755 --- a/src/newt/classes/com/sun/javafx/newt/x11/X11Display.java +++ b/src/newt/classes/com/sun/javafx/newt/x11/X11Display.java @@ -87,11 +87,23 @@ public class X11Display extends Display { protected long getJavaObjectAtom() { return javaObjectAtom; } protected long getWindowDeleteAtom() { return windowDeleteAtom; } + protected void lockDisplay() { + LockDisplay(getHandle()); + } + + protected void unlockDisplay() { + UnlockDisplay(getHandle()); + } + + //---------------------------------------------------------------------- // Internals only // private static native boolean initIDs(); + private native void LockDisplay(long handle); + private native void UnlockDisplay(long handle); + private native void CompleteDisplay(long handle); private native void DispatchMessages(long display, long javaObjectAtom, long windowDeleteAtom); diff --git a/src/newt/classes/com/sun/javafx/newt/x11/X11Window.java b/src/newt/classes/com/sun/javafx/newt/x11/X11Window.java index 46e797c21..94eb98299 100755 --- a/src/newt/classes/com/sun/javafx/newt/x11/X11Window.java +++ b/src/newt/classes/com/sun/javafx/newt/x11/X11Window.java @@ -85,6 +85,25 @@ public class X11Window extends Window { super.windowDestroyed(); } + public synchronized int lockSurface() throws NativeWindowException { + int res = super.lockSurface(); + if(LOCK_SUCCESS == res) { + ((X11Display)(screen.getDisplay())).lockDisplay(); + } + return res; + } + + public synchronized void unlockSurface() { + // prevalidate, before we change data .. + Thread cur = Thread.currentThread(); + if ( getSurfaceLockOwner() != cur ) { + getLockedStack().printStackTrace(); + throw new NativeWindowException(cur+": Not owner, owner is "+getSurfaceLockOwner()); + } + ((X11Display)(screen.getDisplay())).unlockDisplay(); + super.unlockSurface(); + } + public void setVisible(boolean visible) { if(0!=windowHandle && this.visible!=visible) { this.visible=visible; diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 9d3d76bde..5445ca372 100755 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -711,6 +711,8 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, return DefWindowProc(wnd, message, wParam, lParam); } + // DBG_PRINT("*** WindowsWindow: window %p -> %p, 0x%X %d/%d\n", wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); + switch (message) { // diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 0242678d1..097d68cca 100755 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -166,11 +166,15 @@ static jmethodID sendKeyEventID = NULL; static jmethodID displayCompletedID = NULL; -static void _throwNewRuntimeException(JNIEnv *env, const char* msg, ...) +static void _throwNewRuntimeException(Display * unlockDisplay, JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; + if(NULL!=unlockDisplay) { + XUnlockDisplay(unlockDisplay); + } + va_start(ap, msg); vsnprintf(buffer, sizeof(buffer), msg, ap); va_end(ap); @@ -192,6 +196,10 @@ JNIEXPORT jboolean JNICALL Java_com_sun_javafx_newt_x11_X11Display_initIDs { jclass c; + if( 0 == XInitThreads() ) { + fprintf(stderr, "Warning: XInitThreads() failed\n"); + } + displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); if (displayCompletedID == NULL) { return JNI_FALSE; @@ -228,6 +236,37 @@ JNIEXPORT jboolean JNICALL Java_com_sun_javafx_newt_x11_X11Display_initIDs return JNI_TRUE; } +/* + * Class: com_sun_javafx_newt_x11_X11Display + * Method: LockDisplay + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_LockDisplay + (JNIEnv *env, jobject obj, jlong display) +{ + Display * dpy = (Display *)(intptr_t)display; + if(dpy==NULL) { + _throwNewRuntimeException(NULL, env, "given display connection is NULL\n"); + } + XLockDisplay(dpy) ; +} + + +/* + * Class: com_sun_javafx_newt_x11_X11Display + * Method: UnlockDisplay + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_UnlockDisplay + (JNIEnv *env, jobject obj, jlong display) +{ + Display * dpy = (Display *)(intptr_t)display; + if(dpy==NULL) { + _throwNewRuntimeException(NULL, env, "given display connection is NULL\n"); + } + XUnlockDisplay(dpy) ; +} + /* * Class: com_sun_javafx_newt_x11_X11Display @@ -240,22 +279,27 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_CompleteDisplay Display * dpy = (Display *)(intptr_t)display; jlong javaObjectAtom; jlong windowDeleteAtom; + if(dpy==NULL) { - _throwNewRuntimeException(env, "given display connection is NULL\n"); + _throwNewRuntimeException(NULL, env, "given display connection is NULL\n"); } + XLockDisplay(dpy) ; javaObjectAtom = (jlong) XInternAtom(dpy, "JOGL_JAVA_OBJECT", False); if(None==javaObjectAtom) { - _throwNewRuntimeException(env, "could not create Atom JOGL_JAVA_OBJECT, bail out!\n"); + _throwNewRuntimeException(dpy, env, "could not create Atom JOGL_JAVA_OBJECT, bail out!\n"); return; } windowDeleteAtom = (jlong) XInternAtom(dpy, "WM_DELETE_WINDOW", False); if(None==windowDeleteAtom) { - _throwNewRuntimeException(env, "could not create Atom WM_DELETE_WINDOW, bail out!\n"); + _throwNewRuntimeException(dpy, env, "could not create Atom WM_DELETE_WINDOW, bail out!\n"); return; } + // XSetCloseDownMode(dpy, RetainTemporary); // Just a try .. + XUnlockDisplay(dpy) ; + DBG_PRINT1("X11: X11Display_completeDisplay dpy %p\n", dpy); (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom); @@ -285,7 +329,8 @@ static void setJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlon { jobject test = (jobject) getPtrOut32Long(jogl_java_object_data); if( ! (jwindow==test) ) { - _throwNewRuntimeException(env, "Internal Error .. Encoded Window ref not the same %p != %p !\n", jwindow, test); + _throwNewRuntimeException(dpy, env, "Internal Error .. Encoded Window ref not the same %p != %p !\n", jwindow, test); + return; } } @@ -311,24 +356,25 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j &nitems_return, &bytes_after_return, &jogl_java_object_data_pp); if ( Success != res ) { - _throwNewRuntimeException(env, "could not fetch Atom JOGL_JAVA_OBJECT window property (res %d) nitems_return %ld, bytes_after_return %ld, bail out!\n", + _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); 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(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", + _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", res, nitems_return, bytes_after_return, (long)actual_type_return, javaObjectAtom); return NULL; } } + jwindow = (jobject) getPtrOut32Long( (unsigned long *) jogl_java_object_data_pp ) ; XFree(jogl_java_object_data_pp); #ifdef VERBOSE_ON if(JNI_FALSE == (*env)->IsInstanceOf(env, jwindow, newtWindowClz)) { - _throwNewRuntimeException(env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !\n", jwindow); + _throwNewRuntimeException(NULL, env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !\n", jwindow); } #endif return jwindow; @@ -343,10 +389,24 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_DispatchMessages (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong wmDeleteAtom) { Display * dpy = (Display *) (intptr_t) display; - int num_events = 0; + int num_events = 100; + + if ( NULL == dpy ) { + return; + } // Periodically take a break - while( num_events<100 && XPending(dpy)>0 ) { + while( num_events > 0 ) { + + XLockDisplay(dpy) ; + + // num_events = XPending(dpy); // XEventsQueued(dpy, QueuedAfterFlush); // I/O Flush .. + // num_events = XEventsQueued(dpy, QueuedAlready); // Better, no I/O .. + if ( 0 >= XEventsQueued(dpy, QueuedAlready) ) { + XUnlockDisplay(dpy) ; + return; + } + jobject jwindow = NULL; XEvent evt; KeySym keySym; @@ -354,23 +414,41 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_DispatchMessages char text[255]; XNextEvent(dpy, &evt); - num_events++; + num_events--; if( 0==evt.xany.window ) { - _throwNewRuntimeException(env, "event window NULL, bail out!\n"); + _throwNewRuntimeException(dpy, env, "event window NULL, bail out!\n"); + return ; } if(dpy!=evt.xany.display) { - _throwNewRuntimeException(env, "wrong display"); - continue; + _throwNewRuntimeException(dpy, env, "wrong display, bail out!\n"); + return ; } jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom); + if(NULL==jwindow) { // just leave .. _throwNewRuntimeException(env, "could not fetch Java Window object, bail out!\n"); + XUnlockDisplay(dpy) ; return; } switch(evt.type) { + case KeyRelease: + case KeyPress: + if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { + keyChar=text[0]; + } else { + keyChar=0; + } + break; + default: + break; + } + + XUnlockDisplay(dpy) ; + + switch(evt.type) { case ButtonPress: (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, (jint) evt.xbutton.state, @@ -387,21 +465,11 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_DispatchMessages (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); break; case KeyPress: - if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { - keyChar=text[0]; - } else { - keyChar=0; - } (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, (jint) evt.xkey.state, X11KeySym2NewtVKey(keySym), (jchar) keyChar); break; case KeyRelease: - if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { - keyChar=text[0]; - } else { - keyChar=0; - } (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, (jint) evt.xkey.state, X11KeySym2NewtVKey(keySym), (jchar) keyChar); @@ -456,7 +524,7 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Display_DispatchMessages default: DBG_PRINT3("X11: event . unhandled %d 0x%X call 0x%X\n", evt.type, evt.type, evt.xunmap.window); } - } + } } @@ -474,10 +542,13 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Screen_GetScreen { Display * dpy = (Display *)(intptr_t)display; Screen * scrn= NULL; + if(dpy==NULL) { - fprintf(stderr, "[GetScreen] invalid display connection..\n"); + _throwNewRuntimeException(NULL, env, "invalid display connection..\n"); return 0; } + XLockDisplay(dpy); + scrn = ScreenOfDisplay(dpy,screen_index); if(scrn==NULL) { scrn=DefaultScreenOfDisplay(dpy); @@ -485,6 +556,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Screen_GetScreen if(scrn==NULL) { fprintf(stderr, "couldn't get screen ..\n"); } + XUnlockDisplay(dpy) ; return (jlong) (intptr_t) scrn; } @@ -564,15 +636,17 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow DBG_PRINT4( "X11: CreateWindow %x/%d %dx%d\n", x, y, width, height); if(dpy==NULL) { - fprintf(stderr, "[CreateWindow] invalid display connection..\n"); + _throwNewRuntimeException(NULL, env, "invalid display connection..\n"); return 0; } if(visualID<0) { - fprintf(stderr, "[CreateWindow] invalid VisualID ..\n"); + _throwNewRuntimeException(NULL, env, "invalid VisualID ..\n"); return 0; } + XLockDisplay(dpy) ; + XSync(dpy, False); scrn = ScreenOfDisplay(dpy, screen_index); @@ -594,7 +668,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow if (visual==NULL) { - _throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!\n"); + _throwNewRuntimeException(dpy, env, "could not query Visual by given VisualID, bail out!\n"); return 0; } @@ -652,6 +726,8 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow */ } + XUnlockDisplay(dpy) ; + DBG_PRINT2( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); (*env)->CallVoidMethod(env, obj, windowCreatedID, (jlong) window); @@ -670,13 +746,20 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_CloseWindow Window w = (Window)window; jobject jwindow; + if(dpy==NULL) { + _throwNewRuntimeException(NULL, env, "invalid display connection..\n"); + return; + } + XLockDisplay(dpy) ; + jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom); if(NULL==jwindow) { - _throwNewRuntimeException(env, "could not fetch Java Window object, bail out!\n"); + _throwNewRuntimeException(dpy, env, "could not fetch Java Window object, bail out!\n"); return; } if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) { - _throwNewRuntimeException(env, "Internal Error .. Window global ref not the same!\n"); + _throwNewRuntimeException(dpy, env, "Internal Error .. Window global ref not the same!\n"); + return; } (*env)->DeleteGlobalRef(env, jwindow); @@ -690,6 +773,9 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_CloseWindow XSync(dpy, False); XDestroyWindow(dpy, w); XSync(dpy, False); + + XUnlockDisplay(dpy) ; + (*env)->CallVoidMethod(env, obj, windowDestroyedID); } @@ -704,6 +790,13 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setVisible0 Display * dpy = (Display *) (intptr_t) display; Window w = (Window)window; DBG_PRINT1( "X11: setVisible0 vis %d\n", visible); + + if(dpy==NULL) { + _throwNewRuntimeException(NULL, env, "invalid display connection..\n"); + return; + } + XLockDisplay(dpy) ; + XSync(dpy, False); if(visible==JNI_TRUE) { XMapRaised(dpy, w); @@ -720,6 +813,7 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setVisible0 XUnmapWindow(dpy, w); XSync(dpy, False); } + XUnlockDisplay(dpy) ; } #define MWM_FULLSCREEN 1 @@ -746,6 +840,12 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setSize0 DBG_PRINT6( "X11: setSize0 %d/%d %dx%d, dec %d, vis %d\n", x, y, width, height, decorationToggle, setVisible); + if(dpy==NULL) { + _throwNewRuntimeException(NULL, env, "invalid display connection..\n"); + return; + } + XLockDisplay(dpy) ; + XSync(dpy, False); if(setVisible==JNI_TRUE) { @@ -784,6 +884,7 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setSize0 XReparentWindow( dpy, w, parent, x, y ); XSync(dpy, False); + XUnlockDisplay(dpy) ; } /* @@ -799,9 +900,17 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setPosition0 XWindowChanges xwc; DBG_PRINT2( "X11: setPos0 . XConfigureWindow %d/%d\n", x, y); + if(dpy==NULL) { + _throwNewRuntimeException(NULL, env, "invalid display connection..\n"); + return; + } + XLockDisplay(dpy) ; + xwc.x=x; xwc.y=y; XConfigureWindow(dpy, w, CWX|CWY, &xwc); XSync(dpy, False); + + XUnlockDisplay(dpy) ; } |