diff options
author | Sven Gothel <[email protected]> | 2010-11-16 10:36:28 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-11-16 10:36:28 +0100 |
commit | db4d7d198cc826bba871fea39461c3c8a2a3b1c6 (patch) | |
tree | 723c5d4958df50a2ca7443171873e6f854c745a5 /src/newt | |
parent | b3420aeb07f9bef1e4fe5f436524d0b3d66cfaa2 (diff) |
NEWT Lifecycle remodel: Window destroy() !
NEWT's removed:
Window: destoy(boolean unrecoverable)
Display/Screen: get/set DestroyWhenUnused(boolean)
We behave as follows:
- Window.destroy() always decr Screen's reference counter,
which issues destruction when reached zero.
Then Screen does the same for Display ..
- Window.destroy() keeps alive all references,
hence it can be always recreated via setVisible(true).
- Window.destroy() ensures Display's EDT is stopped
if display is destroyed.
- Window.invalidate() actually removes all Object reference,
hence it cannot be recreated or used after it.
This method exist to support a way to cleanup memory, GC.
All test passed on Linux/X11 and Windows
Diffstat (limited to 'src/newt')
11 files changed, 299 insertions, 274 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 19733723e..3e5c0c25e 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -54,43 +54,39 @@ public abstract class Display { } /** - * Manual trigger the native creation.<br> + * Manual trigger the native creation, if it is not done yet.<br> * This is useful to be able to request the {@link javax.media.nativewindow.AbstractGraphicsDevice}, via - * {@link #getGraphicsDevice()}. Otherwise the abstract device won't be available before the dependent components (Screen and Window) - * are realized. + * {@link #getGraphicsDevice()}.<br> + * Otherwise the abstract device won't be available before the dependent components (Screen and Window) are realized. + * <p> + * This method is usually invoke by {@link #addReference()} + * </p> * @throws NativeWindowException if the native creation failed. */ public abstract void createNative() throws NativeWindowException; - public abstract void destroy(); - /** - * @return true if the native display handle is valid and ready to operate, - * otherwise false. - * - * @see #destroy() + * Manually trigger the destruction, incl. native destruction.<br> + * <p> + * This method is usually invoke by {@link #removeReference()} + * </p> */ - public abstract boolean isNativeValid(); + public abstract void destroy(); /** - * @return the value set by {@link #setDestroyWhenUnused(boolean)} - * or the default <code>false</code>. - * - * @see #addReference() - * @see #removeReference() + * Validate EDT running state.<br> + * Stop the running EDT in case this display is destroyed already.<br> + * @return true if EDT has been stopped (destroyed but running), otherwise false. */ - public abstract boolean getDestroyWhenUnused(); + public abstract boolean validateEDT(); /** - * Handles the lifecycle of the native Display instance.<br> - * If set to <code>true</code>, the last {@link #removeReference()} call - * will destroy this instance, otherwise it will stay alive.<br> - * Default is <code>false</code>. + * @return true if the native display handle is valid and ready to operate, + * otherwise false. * - * @see #addReference() - * @see #removeReference() + * @see #destroy() */ - public abstract void setDestroyWhenUnused(boolean v); + public abstract boolean isNativeValid(); /** * @return number of references by Screen diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index e1b15da69..892a2426e 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -162,7 +162,6 @@ public class NewtFactory { Display display = NewtFactory.createDisplay(type, null, true); // local display screen = NewtFactory.createScreen(display, 0); // screen 0 } - screen.setDestroyWhenUnused(true); } final Window win = createWindowImpl(nParentWindow, screen, caps); @@ -189,7 +188,6 @@ public class NewtFactory { protected static Window createWindowImpl(String type, Capabilities caps) { Display display = NewtFactory.createDisplay(type, null, true); // local display Screen screen = NewtFactory.createScreen(display, 0); // screen 0 - screen.setDestroyWhenUnused(true); return WindowImpl.create(null, 0, screen, caps); } diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index a6d45d789..bf8c6f0eb 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -59,38 +59,36 @@ public abstract class Screen { } /** - * Manual trigger the native creation.<br> + * Manual trigger the native creation, if it is not done yet..<br> * This is useful to be able to request the {@link javax.media.nativewindow.AbstractGraphicsScreen}, via - * {@link #getGraphicsScreen()}. Otherwise the abstract device won't be available before the dependent component (Window) - * is realized. + * {@link #getGraphicsScreen()}.<br> + * Otherwise the abstract device won't be available before the dependent component (Window) is realized. + * <p> + * This method is usually invoke by {@link #addReference()} + * </p> + * <p> + * This method invokes {@link Display#addReference()} after creating the native peer,<br> + * which will issue {@link Display#createNative()} if the reference count was 0. + * </p> * @throws NativeWindowException if the native creation failed. */ public abstract void createNative() throws NativeWindowException; - public abstract void destroy(); - - public abstract boolean isNativeValid(); - /** - * @return {@link Display#getDestroyWhenUnused()} - * - * @see #addReference() - * @see #removeReference() - * @see Display#setDestroyWhenUnused(boolean) + * Manually trigger the destruction, incl. native destruction.<br> + * <p> + * This method is usually invoke by {@link #removeReference()} + * </p> + * <p> + * This method invokes {@link Display#removeReference()} after it's own destruction,<br> + * which will issue {@link Display#destroy()} if the reference count becomes 0. + * </p> */ - public abstract boolean getDestroyWhenUnused(); + public abstract void destroy(); - /** - * calls {@link Display#setDestroyWhenUnused(boolean)}. - * - * @see #addReference() - * @see #removeReference() - * @see Display#setDestroyWhenUnused(boolean) - */ - public abstract void setDestroyWhenUnused(boolean v); + public abstract boolean isNativeValid(); /** - * * @return number of references by Window */ public abstract int getReferenceCount(); diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index ba7d51e67..9307ea7f7 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -87,30 +87,24 @@ public interface Window extends NativeWindow, ScreenModeListener { Capabilities getChosenCapabilities(); /** - * - * <p> - * destroys the window and children and releases - * windowing related resources.<br></p> + * Destroy the Window and it's children, incl. native destruction.<br> + * The Window can be recreate via {@link #setVisible(boolean) setVisible(true)}. * <p> - * all other resources and states are kept intact, - * ie listeners, parent handles, size, position and Screen reference.<br></p> - * - * @see #destroy(boolean) + * This method invokes {@link Screen#removeReference()} after it's own destruction,<br> + * which will issue {@link Screen#destroy()} if the reference count becomes 0.<br> + * This destruction sequence shall end up in {@link Display#destroy()}, if all reference counts become 0. + * </p> * @see #invalidate() + * @see #setVisible(boolean) */ void destroy(); /** - * - * Destroys the Window and it's children. - * @param unrecoverable If true, all resources, ie listeners, parent handles, - * size, position and reference to it's Screen will be destroyed as well. - * Otherwise you can recreate the window, via <code>setVisible(true)</code>. - * @see #destroy() - * @see #invalidate(boolean) - * @see #setVisible(boolean) + * Destroys the Window via {@link #destroy()} and clears all Object references, + * eg. all states, size, position, parent handles, list of child Windows and reference to it's Screen.<br> + * This Window cannot be recreated after calling this method anymore.<br> */ - void destroy(boolean unrecoverable); + void invalidate(); /** * <p> diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 3ba721855..a0ab5f9f6 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -193,37 +193,27 @@ public class NewtCanvasAWT extends java.awt.Canvas { } /** - * @see #destroy(boolean) - */ - public final void destroy() { - destroy(false); - } - - /** * Destroys this resource: * <ul> * <li> Make the NEWT Child invisible </li> * <li> Disconnects the NEWT Child from this Canvas NativeWindow, reparent to NULL </li> - * <li> Issues <code>destroy(unrecoverable)</code> on the NEWT Child</li> - * <li> Remove reference to the NEWT Child, if unrecoverable</li> + * <li> Issues <code>destroy()</code> on the NEWT Child</li> + * <li> Remove reference to the NEWT Child</li> * <li> Remove this Canvas from it's parent.</li> * </ul> * @see Window#destroy() - * @see Window#destroy(boolean) */ - public final void destroy(boolean unrecoverable) { + public final void destroy() { if(null!=newtChild) { java.awt.Container cont = getContainer(this); if(DEBUG) { - System.err.println("NewtCanvasAWT.destroy("+unrecoverable+"): "+newtChild+", from "+cont); + System.err.println("NewtCanvasAWT.destroy(): "+newtChild+", from "+cont); } nativeWindow = null; newtChild.setVisible(false); newtChild.reparentWindow(null); - newtChild.destroy(unrecoverable); - if(unrecoverable) { - newtChild = null; - } + newtChild.destroy(); + newtChild=null; if(null!=cont) { cont.remove(this); } diff --git a/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java index e2b3b81ef..7a2a0c9bd 100644 --- a/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java @@ -57,6 +57,7 @@ public class DefaultEDTUtil implements EDTUtil { this.name=new String(Thread.currentThread().getName()+"-"+name+"-EDT-"); this.dispatchMessages=dispatchMessages; this.edt = new EventDispatchThread(threadGroup, name); + this.edt.setDaemon(true); // don't stop JVM from shutdown .. } public final void reset() { @@ -72,6 +73,7 @@ public class DefaultEDTUtil implements EDTUtil { System.err.println(Thread.currentThread()+": EDT reset - edt: "+edt); } this.edt = new EventDispatchThread(threadGroup, name); + this.edt.setDaemon(true); // don't stop JVM from shutdown .. } } diff --git a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java index 7983a1118..2af01c217 100644 --- a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java @@ -181,13 +181,29 @@ public abstract class DisplayImpl extends Display { } } + public boolean validateEDT() { + if(0==refCount && null==aDevice && null != edtUtil && edtUtil.isRunning()) { + stopEDT( new Runnable() { + public void run() { + // nop + } + } ); + edtUtil.waitUntilStopped(); + edtUtil.reset(); + return true; + } + return false; + } + public synchronized final void destroy() { if(DEBUG) { dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); } synchronized(displayList) { displayList.remove(this); - displaysActive--; + if(0 < displaysActive) { + displaysActive--; + } } if(DEBUG) { System.err.println("Display.destroy(): "+this+" "+getThreadName()); @@ -225,7 +241,7 @@ public abstract class DisplayImpl extends Display { if(null == aDevice) { throw new NativeWindowException ("Display.addReference() (refCount "+refCount+") null AbstractGraphicsDevice"); } - return ++refCount; + return refCount++; } @@ -233,9 +249,10 @@ public abstract class DisplayImpl extends Display { if(DEBUG) { System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); } - refCount--; // could become < 0, in case of forced destruction without actual creation/addReference - if(0>=refCount && getDestroyWhenUnused()) { + refCount--; // could become < 0, in case of manual destruction without actual creation/addReference + if(0>=refCount) { destroy(); + refCount=0; // fix < 0 } return refCount; } @@ -244,9 +261,6 @@ public abstract class DisplayImpl extends Display { return refCount; } - public final boolean getDestroyWhenUnused() { return destroyWhenUnused; } - public final void setDestroyWhenUnused(boolean v) { destroyWhenUnused=v; } - protected abstract void createNativeImpl(); protected abstract void closeNativeImpl(); @@ -275,7 +289,7 @@ public abstract class DisplayImpl extends Display { return ( null == name ) ? nilString : name ; } - protected static final String getFQName(String type, String name, int id) { + private static final String getFQName(String type, String name, int id) { if(null==type) type=nilString; if(null==name) name=nilString; StringBuffer sb = new StringBuffer(); @@ -284,7 +298,7 @@ public abstract class DisplayImpl extends Display { sb.append(name); sb.append("-"); sb.append(id); - return sb.toString(); + return sb.toString().intern(); } public final long getHandle() { diff --git a/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java index f3c7b8415..30dc945db 100644 --- a/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java @@ -68,13 +68,13 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { // nop } - public void invalidate(boolean unrecoverable) { + protected void invalidate(boolean unrecoverable) { super.invalidate(unrecoverable); surfaceHandle = 0; } - public synchronized void destroy(boolean unrecoverable) { - super.destroy(unrecoverable); + public synchronized void destroy() { + super.destroy(); surfaceHandle = 0; } diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java index c9d1a9c32..071122a68 100644 --- a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java @@ -50,7 +50,8 @@ import java.util.ArrayList; import java.util.List; public abstract class ScreenImpl extends Screen implements ScreenModeListener { - protected static final boolean DisableScreenModeImpl = Debug.debug("Screen.DisableScreenModeImpl"); + protected static final boolean DEBUG_TEST_SCREENMODE_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableScreenMode", true); + protected DisplayImpl display; protected int screen_idx; protected String fqname; @@ -112,7 +113,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); screen.display = (DisplayImpl) display; screen.screen_idx = idx; - screen.fqname = display.getFQName()+idx; + screen.fqname = (display.getFQName()+idx).intern(); screen.hashCode = screen.fqname.hashCode(); screenList.add(screen); if(DEBUG) { @@ -157,7 +158,9 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { synchronized(screenList) { screenList.remove(this); - screensActive--; + if(0 < screensActive) { + screensActive--; + } } if ( null != aScreen ) { @@ -183,11 +186,15 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { public synchronized final int removeReference() { if(DEBUG) { - System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + String msg = "Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1); + // Throwable t = new Throwable(msg); + // t.printStackTrace(); + System.err.println(msg); } - refCount--; // could become < 0, in case of forced destruction without actual creation/addReference - if(0>=refCount && getDestroyWhenUnused()) { + refCount--; // could become < 0, in case of manual destruction without actual creation/addReference + if(0>=refCount) { destroy(); + refCount=0; // fix < 0 } return refCount; } @@ -196,13 +203,6 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { return refCount; } - public final boolean getDestroyWhenUnused() { - return display.getDestroyWhenUnused(); - } - public final void setDestroyWhenUnused(boolean v) { - display.setDestroyWhenUnused(v); - } - protected abstract void createNativeImpl(); protected abstract void closeNativeImpl(); @@ -260,7 +260,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { ScreenMode smU = null; ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); if(null != sms) { - ScreenMode sm0 = ( DisableScreenModeImpl ) ? null : getCurrentScreenModeImpl(); + ScreenMode sm0 = ( DEBUG_TEST_SCREENMODE_DISABLED ) ? null : getCurrentScreenModeImpl(); if(null == sm0) { return null; } @@ -415,7 +415,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { ArrayHashSet screenModes = collectNativeScreenModes(screenModesIdx2NativeIdx); sms = new ScreenModeStatus(screenModes, screenModesIdx2NativeIdx); if(null!=screenModes && screenModes.size()>0) { - ScreenMode originalScreenMode = ( DisableScreenModeImpl ) ? null : getCurrentScreenModeImpl(); + ScreenMode originalScreenMode = ( DEBUG_TEST_SCREENMODE_DISABLED ) ? null : getCurrentScreenModeImpl(); if(null != originalScreenMode) { ScreenMode originalScreenMode0 = (ScreenMode) screenModes.get(originalScreenMode); // unify via value hash if(null == originalScreenMode0) { @@ -450,7 +450,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { + ScreenModeUtil.NUM_SURFACE_SIZE_PROPERTIES - 1 ; // index 0 based do { - if(DisableScreenModeImpl) { + if(DEBUG_TEST_SCREENMODE_DISABLED) { smProps = null; } else if(0 == num) { smProps = getScreenModeFirstImpl(); diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java index c34081ebf..9f744be82 100644 --- a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java @@ -71,6 +71,59 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); + private RecursiveLock windowLock = new RecursiveLock(); + private long windowHandle; + private ScreenImpl screen; + private boolean screenReferenceAdded = false; + private NativeWindow parentWindow; + private long parentWindowHandle; + protected AbstractGraphicsConfiguration config; + protected Capabilities caps; + protected boolean fullscreen, visible, hasFocus; + protected int width, height, x, y; + protected int nfs_width, nfs_height, nfs_x, nfs_y; // non fullscreen dimensions .. + protected String title = "Newt Window"; + protected boolean undecorated = false; + private LifecycleHook lifecycleHook = null; + + private DestroyAction destroyAction = new DestroyAction(); + private boolean handleDestroyNotify = true; + + private ReparentActionRecreate reparentActionRecreate = new ReparentActionRecreate(); + + private RequestFocusAction requestFocusAction = new RequestFocusAction(); + private FocusRunnable focusAction = null; + + private Object surfaceUpdatedListenersLock = new Object(); + private ArrayList surfaceUpdatedListeners; + + private Object childWindowsLock = new Object(); + private ArrayList childWindows; + + private ArrayList mouseListeners; + private int mouseButtonPressed; // current pressed mouse button number + private long lastMousePressed; // last time when a mouse button was pressed + private int lastMouseClickCount; // last mouse button click count + + private ArrayList keyListeners; + + private ArrayList windowListeners; + private boolean repaintQueued = false; + + private void initializeStates() { + invalidate(true); + + childWindows = new ArrayList(); + surfaceUpdatedListeners = new ArrayList(); + windowListeners = new ArrayList(); + mouseListeners = new ArrayList(); + + mouseButtonPressed = 0; // current pressed mouse button number + lastMousePressed = 0; // last time when a mouse button was pressed + lastMouseClickCount = 0; // last mouse button click count + keyListeners = new ArrayList(); + } + // Workaround for initialization order problems on Mac OS X // between native Newt and (apparently) Fmod -- if Fmod is // initialized first then the connection to the window server @@ -89,8 +142,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod // Construction Methods // - private static Class getWindowClass(String type) - throws ClassNotFoundException + private static Class getWindowClass(String type) + throws ClassNotFoundException { Class windowClass = NewtFactory.getCustomClass(type, "Window"); if(null==windowClass) { @@ -120,7 +173,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod windowClass = OffscreenWindow.class; } WindowImpl window = (WindowImpl) windowClass.newInstance(); - window.invalidate(true); + window.initializeStates(); window.parentWindow = parentWindow; window.parentWindowHandle = parentWindowHandle; window.screen = (ScreenImpl) screen; @@ -145,7 +198,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments)); } WindowImpl window = (WindowImpl) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; - window.invalidate(true); + window.initializeStates(); window.screen = (ScreenImpl) screen; window.caps = (Capabilities)caps.clone(); return window; @@ -174,7 +227,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod * Surface not locked yet.<br> * Called not necessarily from EDT. */ - void destroyActionPreLock(boolean unrecoverable); + void destroyActionPreLock(); /** * Invoked before Window destroy action, @@ -182,7 +235,14 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod * Surface locked.<br> * Called from EDT while window is locked. */ - void destroyActionInLock(boolean unrecoverable); + void destroyActionInLock(); + + /** + * Invoked after destruction from Window's invalidate method.<br> + * Called while window is locked. + * @param unrecoverable + */ + void invalidate(boolean unrecoverable); /** * Invoked for expensive modifications, ie while reparenting and ScreenMode change.<br> @@ -201,41 +261,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod void resumeRenderingAction(); } - private LifecycleHook lifecycleHook = null; - private RecursiveLock windowLock = new RecursiveLock(); - private long windowHandle; - private ScreenImpl screen; - private boolean screenReferenced = false; - private NativeWindow parentWindow; - private long parentWindowHandle; - - protected AbstractGraphicsConfiguration config; - protected Capabilities caps; - protected boolean fullscreen, visible, hasFocus; - protected int width, height, x, y; - protected int nfs_width, nfs_height, nfs_x, nfs_y; // non fullscreen dimensions .. - - protected String title = "Newt Window"; - protected boolean undecorated = false; - private boolean handleDestroyNotify = true; - - private final void destroyScreen() { - if(null!=screen) { - if(screenReferenced) { - screen.removeReference(); - screenReferenced = false; - } - screen = null; - } - } - private final void setScreen(ScreenImpl newScreen) { - if(screenReferenced) { - screenReferenced = false; - screen.removeReference(); - } - screen = newScreen; - } - private boolean createNative() { if(DEBUG_IMPLEMENTATION) { System.err.println("Window.createNative() START ("+getThreadName()+", "+this+")"); @@ -246,10 +271,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } try { if(validateParentWindowHandle()) { - if(!screenReferenced) { - screenReferenced = true; - screen.addReference(); + if(screenReferenceAdded) { + throw new InternalError("XXX"); } + screen.addReference(); + screenReferenceAdded = true; createNativeImpl(); setVisibleImpl(true, x, y, width, height); screen.addScreenModeListener(this); @@ -265,6 +291,36 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod return 0 != windowHandle ; } + private void removeScreenReference() { + if(screenReferenceAdded) { + // be nice, probably already called recursive via + // closeAndInvalidate() -> closeNativeIml() -> .. -> windowDestroyed() -> closeAndInvalidate() ! + // or via reparentWindow .. etc + screenReferenceAdded = false; + screen.removeReference(); + } + } + + private void closeAndInvalidate() { + windowLock.lock(); + try { + if( null != screen ) { + if( 0 != windowHandle ) { + screen.removeScreenModeListener(WindowImpl.this); + closeNativeImpl(); + removeScreenReference(); + } + Display dpy = screen.getDisplay(); + if(null != dpy) { + dpy.validateEDT(); + } + } + invalidate(false); + } finally { + windowLock.unlock(); + } + } + private boolean validateParentWindowHandle() { if(null!=parentWindow) { parentWindowHandle = getNativeWindowHandle(parentWindow); @@ -446,9 +502,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod // NativeWindow // - public final void destroy() { - destroy(false); - } + // public final void destroy() - see below public final NativeWindow getParent() { return parentWindow; @@ -649,11 +703,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } class DestroyAction implements Runnable { - boolean unrecoverable; - - public DestroyAction(boolean unrecoverable) { - this.unrecoverable = unrecoverable; - } public void run() { windowLock.lock(); try { @@ -663,47 +712,29 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod // Childs first .. synchronized(childWindowsLock) { - // avoid ConcurrentModificationException: parent -> child -> parent.removeChild(this) - ArrayList clonedChildWindows = (ArrayList) childWindows.clone(); - while( clonedChildWindows.size() > 0 ) { - NativeWindow nw = (NativeWindow) clonedChildWindows.remove(0); - if(nw instanceof WindowImpl) { - ((WindowImpl)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - if(unrecoverable) { - ((WindowImpl)nw).destroy(unrecoverable); - } - } else { - nw.destroy(); + if(childWindows.size()>0) { + // avoid ConcurrentModificationException: parent -> child -> parent.removeChild(this) + ArrayList clonedChildWindows = (ArrayList) childWindows.clone(); + while( clonedChildWindows.size() > 0 ) { + NativeWindow nw = (NativeWindow) clonedChildWindows.remove(0); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); + ((WindowImpl)nw).destroy(); + } else { + nw.destroy(); + } } } } if(null!=lifecycleHook) { - lifecycleHook.destroyActionInLock(unrecoverable); + lifecycleHook.destroyActionInLock(); } - // Now us .. - if(unrecoverable) { - if(null!=parentWindow && parentWindow instanceof Window) { - ((Window)parentWindow).removeChild(WindowImpl.this); - } - synchronized(childWindowsLock) { - childWindows = new ArrayList(); - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList(); - } - windowListeners = new ArrayList(); - mouseListeners = new ArrayList(); - keyListeners = new ArrayList(); - } - if( null != screen && 0 != windowHandle ) { - screen.removeScreenModeListener(WindowImpl.this); - closeNativeImpl(); - } - invalidate(unrecoverable); + closeAndInvalidate(); + if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") END "+getThreadName()/*+", "+WindowImpl.this*/); + System.err.println("Window.destroy() END "+getThreadName()/*+", "+WindowImpl.this*/); } } finally { windowLock.unlock(); @@ -711,36 +742,27 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } } - public void destroy(boolean unrecoverable) { + public void destroy() { if( isValid() ) { if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window.destroy(unrecoverable: "+unrecoverable+") START "+getThreadName()/*+", "+this*/); + String msg = new String("Window.destroy() START "+getThreadName()/*+", "+this*/); System.err.println(msg); //Exception ee = new Exception(msg); //ee.printStackTrace(); - } + } if(null!=lifecycleHook) { - lifecycleHook.destroyActionPreLock(unrecoverable); + lifecycleHook.pauseRenderingAction(); + } + if(null!=lifecycleHook) { + lifecycleHook.destroyActionPreLock(); } - DestroyAction destroyAction = new DestroyAction(unrecoverable); runOnEDTIfAvail(true, destroyAction); } } - /** - * <p> - * render all native window information invalid, - * as if the native window was destroyed.<br></p> - * <p> - * all other resources and states are kept intact, - * ie listeners, parent handles and size, position etc.<br></p> - * - * @see #destroy() - * @see #destroy(boolean) - * @see #invalidate(boolean) - */ public final void invalidate() { - invalidate(false); + destroy(); + invalidate(true); } /** @@ -757,16 +779,49 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { String msg = new String("!!! Window Invalidate(unrecoverable: "+unrecoverable+") "+getThreadName()); System.err.println(msg); - // Exception e = new Exception(msg); - // e.printStackTrace(); + // Throwable t = new Throwable(msg); + // t.printStackTrace(); + } + + // Childs first .. + synchronized(childWindowsLock) { + // avoid ConcurrentModificationException: parent -> child -> parent.removeChild(this) + if(null!=childWindows && childWindows.size()>0) { + ArrayList clonedChildWindows = (ArrayList) childWindows.clone(); + while( clonedChildWindows.size() > 0 ) { + NativeWindow nw = (NativeWindow) clonedChildWindows.remove(0); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).invalidate(unrecoverable); + } + } + } } + + if(null!=lifecycleHook) { + lifecycleHook.invalidate(unrecoverable); + } + windowHandle = 0; visible = false; fullscreen = false; hasFocus = false; if(unrecoverable) { - destroyScreen(); + if(null!=parentWindow && parentWindow instanceof Window) { + ((Window)parentWindow).removeChild(WindowImpl.this); + } + screen = null; + + synchronized(childWindowsLock) { + childWindows = null; + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners = null; + } + windowListeners = null; + mouseListeners = null; + keyListeners = null; + parentWindowHandle = 0; parentWindow = null; caps = null; @@ -794,10 +849,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod this.reparentAction = -1; // ensure it's set } - public int getStrategy() { + public final int getStrategy() { return reparentAction; } + private final void setScreen(ScreenImpl newScreen) { + WindowImpl.this.removeScreenReference(); + screen = newScreen; + } + public void run() { boolean wasVisible; @@ -846,9 +906,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod if(null==newParentWindowNEWT) { throw new NativeWindowException("Reparenting with non NEWT Window type only available after it's realized: "+newParentWindow); } - // Destroy this window (handle screen + native) and use parent's Screen. + // Destroy this window and use parent's Screen. // It may be created properly when the parent is made visible. - destroy(false); + destroy(); setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); reparentAction = ACTION_NATIVE_CREATION_PENDING; } else if(newParentWindow != getParent()) { @@ -862,7 +922,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, getScreen()); if( getScreen() != newScreen ) { // auto destroy on-the-fly created Screen/Display - newScreen.setDestroyWhenUnused(true); setScreen( (ScreenImpl) newScreen ); } } @@ -873,15 +932,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { - // Destroy this window (handle screen + native) and - // may create a new compatible Screen/Display and - // mark it for creation. - destroy(false); + // Destroy this window, may create a new compatible Screen/Display, + // and mark it for creation. + destroy(); if(null!=newParentWindowNEWT) { setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); } else { setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, getScreen()) ); - screen.setDestroyWhenUnused(true); } reparentAction = ACTION_NATIVE_CREATION; } else { @@ -906,9 +963,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod // Already Top Window reparentAction = ACTION_UNCHANGED; } else if( !isNativeValid() || DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate ) { - // Destroy this window (handle screen + native), - // keep Screen/Display and mark it for creation. - destroy(false); + // Destroy this window and mark it for [pending] creation. + destroy(); if( 0<width*height ) { reparentAction = ACTION_NATIVE_CREATION; } else { @@ -1015,7 +1071,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod if(DEBUG_IMPLEMENTATION) { System.err.println("Window.reparent: native reparenting failed ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentWindowHandle)+" - Trying recreation"); } - destroy(false); + destroy(); reparentAction = ACTION_NATIVE_CREATION ; } } @@ -1065,7 +1121,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } } } - private ReparentActionRecreate reparentActionRecreate = new ReparentActionRecreate(); public final int reparentWindow(NativeWindow newParent) { return reparentWindow(newParent, false); @@ -1075,7 +1130,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod int reparentActionStrategy = ReparentAction.ACTION_INVALID; if(isValid()) { if(null!=lifecycleHook) { - // pause animation lifecycleHook.pauseRenderingAction(); } try { @@ -1084,7 +1138,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod reparentActionStrategy = reparentAction.getStrategy(); } finally { if(null!=lifecycleHook) { - // resume animation lifecycleHook.resumeRenderingAction(); } } @@ -1316,7 +1369,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod WindowImpl.this.requestFocusImpl(false); } } - RequestFocusAction requestFocusAction = new RequestFocusAction(); protected void enqueueRequestFocus(boolean wait) { runOnEDTIfAvail(wait, requestFocusAction); @@ -1345,7 +1397,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } return res; } - protected FocusRunnable focusAction = null; class SetPositionActionImpl implements Runnable { int x, y; @@ -1475,7 +1526,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } if(null!=lifecycleHook) { - // pause animation lifecycleHook.pauseRenderingAction(); } } @@ -1494,7 +1544,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } if(null!=lifecycleHook) { - // resume animation lifecycleHook.resumeRenderingAction(); sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener } @@ -1504,9 +1553,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod // Child Window Management // - private ArrayList childWindows = new ArrayList(); - private Object childWindowsLock = new Object(); - public final void removeChild(NativeWindow win) { synchronized(childWindowsLock) { childWindows.remove(win); @@ -1591,15 +1637,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod } return true; } - protected boolean repaintQueued = false; // // SurfaceUpdatedListener Support // - private ArrayList surfaceUpdatedListeners = new ArrayList(); - private Object surfaceUpdatedListenersLock = new Object(); - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { addSurfaceUpdatedListener(-1, l); } @@ -1660,11 +1702,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod // // MouseListener/Event Support // - private ArrayList mouseListeners = new ArrayList(); - private int mouseButtonPressed = 0; // current pressed mouse button number - private long lastMousePressed = 0; // last time when a mouse button was pressed - private int lastMouseClickCount = 0; // last mouse button click count - public void sendMouseEvent(int eventType, int modifiers, int x, int y, int button, int rotation) { doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation); @@ -1857,8 +1894,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod return (KeyListener[]) keyListeners.toArray(); } - private ArrayList keyListeners = new ArrayList(); - protected void consumeKeyEvent(KeyEvent e) { if(DEBUG_KEY_EVENT) { System.err.println("consumeKeyEvent: "+e); @@ -1892,8 +1927,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod enqueueEvent( wait, new WindowEvent(eventType, this, System.currentTimeMillis()) ); } - private ArrayList windowListeners = new ArrayList(); - public void addWindowListener(WindowListener l) { addWindowListener(-1, l); } @@ -2055,7 +2088,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenMod if(DEBUG_IMPLEMENTATION) { System.err.println("Window.windowDestroyed "+getThreadName()); } - invalidate(); + closeAndInvalidate(); } public void windowRepaint(int x, int y, int width, int height) { diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index f84c65cb7..72963eaa3 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -246,8 +246,8 @@ public class GLWindow implements GLAutoDrawable, Window { // Window.LifecycleHook Implementation // - public final void destroy(boolean unrecoverable) { - window.destroy(unrecoverable); + public final void destroy() { + window.destroy(); } public final void setVisible(boolean visible) { @@ -282,23 +282,14 @@ public class GLWindow implements GLAutoDrawable, Window { DisposeAction disposeAction = new DisposeAction(); /** Window.LifecycleHook */ - public synchronized void destroyActionPreLock(boolean unrecoverable) { - GLAnimatorControl animator = GLWindow.this.getAnimator(); - if(null!=animator) { - if(unrecoverable) { - if(animator.isStarted()) { - animator.stop(); - } - } else if(animator.isAnimating()) { - animator.pause(); - } - } + public synchronized void destroyActionPreLock() { + // nop } /** Window.LifecycleHook */ - public synchronized void destroyActionInLock(boolean unrecoverable) { + public synchronized void destroyActionInLock() { if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { - String msg = new String("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", start"); + String msg = new String("GLWindow.destroy() "+Thread.currentThread()+", start"); System.err.println(msg); //Exception e1 = new Exception(msg); //e1.printStackTrace(); @@ -320,12 +311,25 @@ public class GLWindow implements GLAutoDrawable, Window { context = null; drawable = null; - if(unrecoverable) { - helper=null; + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + System.err.println("GLWindow.destroy() "+Thread.currentThread()+", fin"); } + } + /** Window.LifecycleHook */ + public synchronized void invalidate(boolean unrecoverable) { if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { - System.err.println("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", fin"); + String msg = new String("GLWindow.invalidate("+unrecoverable+") "+Thread.currentThread()+", start"); + System.err.println(msg); + //Exception e1 = new Exception(msg); + //e1.printStackTrace(); + } + if(unrecoverable) { + GLAnimatorControl ctrl = GLWindow.this.getAnimator(); + if ( null!=ctrl && ctrl.isStarted() ) { + ctrl.stop(); + } + helper=null; } } @@ -635,10 +639,6 @@ public class GLWindow implements GLAutoDrawable, Window { return null!=drawable ? drawable.getHandle() : 0; } - public final void destroy() { - window.destroy(); - } - public final int getX() { return window.getX(); } @@ -878,7 +878,7 @@ public class GLWindow implements GLAutoDrawable, Window { }); glWindow.setVisible(true); - glWindow.destroy(true); + glWindow.invalidate(); } } |