diff options
author | Sven Gothel <[email protected]> | 2012-05-01 09:21:14 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-05-01 09:21:14 +0200 |
commit | 4e0eb391d6c64f956ea5c87c0385ab48a24b2175 (patch) | |
tree | 69f0f45c73fc7fe2a95a678e75fa5fb4262911db /src | |
parent | 5742b1faa210401470032ef129e56a83c47fd046 (diff) |
Fix Bug 560 and NEWT window closing behavior in general for all platforms.
- NEWT/WindowImpl:
- 'void windowDestroyNotify()' -> 'boolean windowDestroyNotify(boolean force)', allowing to signal a forced close,
as well as replying whether the window has been closed. (called by native code)
- destroy(): set states before releasing the window lock
- NEWT/X11: Pass windowDeleteAtom for reconfigure window, in case of reparenting child to top-level
- NEWT/OSX:
- Add 'BOOL windowShouldClose()' impl., ie. having a chance to reject the close attempt
- Common impl. for 'windowShouldClose' and 'windowWillClose' -> 'windowClosingImpl'
utilizing new 'windowDestroyNotify' code (see above).
Fixes bug 560.
- NEWT/JOGLNewtApplet1Run: Refine out-of browser window behavior for window-close button
- default: move NEWT window back to browser parent
- closeable: close NEWT window
- jogl-test-applets: Add NApplet-Closeable test (Applet out-of browser window is closable)
Diffstat (limited to 'src')
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java | 9 | ||||
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java | 27 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/WindowImpl.java | 42 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java | 5 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java | 14 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/X11Window.java | 8 | ||||
-rw-r--r-- | src/newt/native/KDWindow.c | 8 | ||||
-rw-r--r-- | src/newt/native/MacWindow.m | 5 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.h | 8 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.m | 35 | ||||
-rw-r--r-- | src/newt/native/WindowsWindow.c | 4 | ||||
-rw-r--r-- | src/newt/native/X11Display.c | 9 | ||||
-rw-r--r-- | src/newt/native/X11Window.c | 5 | ||||
-rw-r--r-- | src/test/jogamp/newt/WindowImplAccess.java | 2 |
14 files changed, 139 insertions, 42 deletions
diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java index a052f6f97..82562636b 100755 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java @@ -36,6 +36,7 @@ import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import javax.media.nativewindow.WindowClosingProtocol; import javax.media.opengl.FPSCounter; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; @@ -64,7 +65,7 @@ import com.jogamp.newt.opengl.GLWindow; * </p> * * <p> - * Example of an applet tag using GearsES2 in an undecorated, translucent and always-on-top window: + * Example of an applet tag using GearsES2 in an undecorated, translucent, closeable and always-on-top window: * <pre> <applet width=1 height=1> <param name="java_arguments" value="-Dsun.java2d.noddraw=true"> @@ -73,6 +74,7 @@ import com.jogamp.newt.opengl.GLWindow; <param name="gl_swap_interval" value="1"> <param name="gl_undecorated" value="true"> <param name="gl_alwaysontop" value="true"> + <param name="gl_closeable" value="true"> <param name="gl_alpha" value="1"> <param name="gl_multisamplebuffer" value="0"> <param name="gl_opaque" value="false"> @@ -115,6 +117,7 @@ public class JOGLNewtApplet1Run extends Applet { boolean glTrace=false; boolean glUndecorated=false; boolean glAlwaysOnTop=false; + boolean glCloseable=false; boolean glOpaque=true; int glAlphaBits=0; int glNumMultisampleBuffer=0; @@ -128,6 +131,7 @@ public class JOGLNewtApplet1Run extends Applet { glTrace = JOGLNewtAppletBase.str2Bool(getParameter("gl_trace"), glTrace); glUndecorated = JOGLNewtAppletBase.str2Bool(getParameter("gl_undecorated"), glUndecorated); glAlwaysOnTop = JOGLNewtAppletBase.str2Bool(getParameter("gl_alwaysontop"), glAlwaysOnTop); + glCloseable = JOGLNewtAppletBase.str2Bool(getParameter("gl_closeable"), glCloseable); glOpaque = JOGLNewtAppletBase.str2Bool(getParameter("gl_opaque"), glOpaque); glAlphaBits = JOGLNewtAppletBase.str2Int(getParameter("gl_alpha"), glAlphaBits); glNumMultisampleBuffer = JOGLNewtAppletBase.str2Int(getParameter("gl_multisamplebuffer"), glNumMultisampleBuffer); @@ -157,6 +161,7 @@ public class JOGLNewtApplet1Run extends Applet { System.err.println("glTrace: "+glTrace); System.err.println("glUndecorated: "+glUndecorated); System.err.println("glAlwaysOnTop: "+glAlwaysOnTop); + System.err.println("glCloseable: "+glCloseable); System.err.println("glOpaque: "+glOpaque); System.err.println("glAlphaBits: "+glAlphaBits); System.err.println("glNumMultisampleBuffer: "+glNumMultisampleBuffer); @@ -166,6 +171,7 @@ public class JOGLNewtApplet1Run extends Applet { base = new JOGLNewtAppletBase(glEventListenerClazzName, glSwapInterval, glNoDefaultKeyListener, + glCloseable, glDebug, glTrace); @@ -181,6 +187,7 @@ public class JOGLNewtApplet1Run extends Applet { glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err); glWindow.setUndecorated(glUndecorated); glWindow.setAlwaysOnTop(glAlwaysOnTop); + glWindow.setDefaultCloseOperation(glCloseable ? WindowClosingProtocol.DISPOSE_ON_CLOSE : WindowClosingProtocol.DO_NOTHING_ON_CLOSE); container.setLayout(new BorderLayout()); if(appletDebugTestBorder) { container.add(new Button("North"), BorderLayout.NORTH); diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java index 67da50210..9ffc24372 100755 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java @@ -32,6 +32,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.WindowClosingProtocol; import javax.media.opengl.FPSCounter; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; @@ -43,8 +44,10 @@ import jogamp.newt.Debug; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.WindowUpdateEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.util.Animator; @@ -58,6 +61,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { String glEventListenerClazzName; int glSwapInterval; boolean noDefaultKeyListener; + boolean glClosable; boolean glDebug; boolean glTrace; @@ -70,12 +74,14 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { public JOGLNewtAppletBase(String glEventListenerClazzName, int glSwapInterval, boolean noDefaultKeyListener, + boolean glClosable, boolean glDebug, boolean glTrace) { this.glEventListenerClazzName=glEventListenerClazzName; this.glSwapInterval=glSwapInterval; this.noDefaultKeyListener = noDefaultKeyListener; + this.glClosable = glClosable; this.glDebug = glDebug; this.glTrace = glTrace; } @@ -152,9 +158,25 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { init(Thread.currentThread().getThreadGroup(), glWindow); } - public void init(ThreadGroup tg, GLWindow glWindow) { + public void init(ThreadGroup tg, final GLWindow glWindow) { isValid = false; this.glWindow = glWindow; + this.glWindow.addWindowListener(new WindowAdapter() { + // Closing action: back to parent! + @Override + public void windowDestroyNotify(WindowEvent e) { + if( WindowClosingProtocol.DO_NOTHING_ON_CLOSE == glWindow.getDefaultCloseOperation() ) { + if(null == glWindow.getParent()) { + // we may be called directly by the native EDT + new Thread(new Runnable() { + public void run() { + // try { Thread.sleep(10); } catch (InterruptedException e) { } + glWindow.reparentWindow(awtParent); + } + }).start(); + } + } + } } ); glEventListener = createInstance(glEventListenerClazzName); if(null == glEventListener) { @@ -277,6 +299,9 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.reparentWindow(awtParent); } else { glWindow.reparentWindow(null); + if(glClosable) { + glWindow.setDefaultCloseOperation(WindowClosingProtocol.DISPOSE_ON_CLOSE); + } } } } diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 3d465e45c..5e393f7c5 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -66,6 +66,7 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.util.DimensionImmutable; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; @@ -428,12 +429,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * The implementation should invoke the referenced java state callbacks * to notify this Java object of state changes.</p> * - * @see #windowDestroyNotify() + * @see #windowDestroyNotify(boolean) * @see #focusChanged(boolean, boolean) * @see #visibleChanged(boolean, boolean) * @see #sizeChanged(int,int) * @see #positionChanged(boolean,int, int) - * @see #windowDestroyNotify() + * @see #windowDestroyNotify(boolean) */ protected abstract void createNativeImpl(); @@ -908,16 +909,18 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer System.err.println("Window.destroy() END "+getThreadName()/*+", "+WindowImpl.this*/); } } finally { + // update states before release window lock + setWindowHandle(0); + visible = false; + fullscreen = false; + hasFocus = false; + parentWindowHandle = 0; + windowLock.unlock(); } if(animatorPaused) { lifecycleHook.resumeRenderingAction(); } - setWindowHandle(0); - visible = false; - fullscreen = false; - hasFocus = false; - parentWindowHandle = 0; // these refs shall be kept alive - resurrection via setVisible(true) /** @@ -1525,8 +1528,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** * If set to true, the default value, this NEWT Window implementation will - * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.<br> - * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify()}. + * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify(boolean)} implementation.<br> + * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify(boolean)}. */ public void setHandleDestroyNotify(boolean b) { handleDestroyNotify = b; @@ -2498,21 +2501,34 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } - protected void windowDestroyNotify() { + /** + * Triggered by implementation's WM events or programmatically + * + * @param force if true, overrides {@link #setDefaultCloseOperation(int)} with {@link WindowClosingProtocol#DISPOSE_ON_CLOSE} + * and hence force destruction. Otherwise is follows the user settings. + * @return true if this window is no more valid and hence has been destroyed, otherwise false. + */ + protected boolean windowDestroyNotify(boolean force) { if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyNotify START "+getThreadName()); + System.err.println("Window.windowDestroyNotify(force: "+force+") START "+getThreadName()+": "+this); + } + if(force) { + setDefaultCloseOperation(WindowClosingProtocol.DISPOSE_ON_CLOSE); } // send synced destroy notifications enqueueWindowEvent(true, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - if(handleDestroyNotify && DISPOSE_ON_CLOSE == defaultCloseOperation) { + if(handleDestroyNotify && DISPOSE_ON_CLOSE == getDefaultCloseOperation()) { destroy(); } + + final boolean destroyed = !isNativeValid(); if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyeNotify END "+getThreadName()); + System.err.println("Window.windowDestroyNotify(force: "+force+") END "+getThreadName()+": destroyed "+destroyed+", "+this); } + return destroyed; } public void windowRepaint(int x, int y, int width, int height) { diff --git a/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java b/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java index 4547db831..63d5f7003 100644 --- a/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java +++ b/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java @@ -329,8 +329,7 @@ public class AndroidWindow extends jogamp.newt.WindowImpl implements Callback2 { if(0!=surfaceHandle && androidFormat != aFormat ) { // re-create Log.d(MD.TAG, "surfaceChanged (destroy old)"); - windowDestroyNotify(); - if(isNativeValid()) { + if(!windowDestroyNotify(true)) { destroy(); } surfaceHandle = 0; @@ -371,7 +370,7 @@ public class AndroidWindow extends jogamp.newt.WindowImpl implements Callback2 { public void surfaceDestroyed(SurfaceHolder holder) { Log.d(MD.TAG, "surfaceDestroyed"); - windowDestroyNotify(); + windowDestroyNotify(true); // actually too late .. however .. } public void surfaceRedrawNeeded(SurfaceHolder holder) { diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java index c926d44ee..b45c60e69 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java @@ -77,19 +77,19 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable, DriverCl protected void closeNativeImpl() { try { if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } - if (getWindowHandle() != 0) { - close0(getWindowHandle()); + final long handle = getWindowHandle(); + setWindowHandle(0); + surfaceHandle = 0; + sscSurfaceHandle = 0; + isOffscreenInstance = false; + if (0 != handle) { + close0(handle); } } catch (Throwable t) { if(DEBUG_IMPLEMENTATION) { Exception e = new Exception("Warning: closeNative failed - "+Thread.currentThread().getName(), t); e.printStackTrace(); } - } finally { - setWindowHandle(0); - surfaceHandle = 0; - sscSurfaceHandle = 0; - isOffscreenInstance = false; } } diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java index 703b18272..143b94a57 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java @@ -117,8 +117,10 @@ public class X11Window extends WindowImpl { // client position -> top-level window position x -= i.getLeftWidth() ; y -= i.getTopHeight() ; - } - reconfigureWindow0( getDisplayEDTHandle(), getScreenIndex(), getParentWindowHandle(), getWindowHandle(), + } + final X11Display display = (X11Display) getScreen().getDisplay(); + reconfigureWindow0( getDisplayEDTHandle(), getScreenIndex(), + getParentWindowHandle(), getWindowHandle(), display.getWindowDeleteAtom(), x, y, width, height, flags); return true; @@ -243,7 +245,7 @@ public class X11Window extends WindowImpl { int x, int y, int width, int height, boolean autoPosition, int flags); private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom); private native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long windowHandle, - int x, int y, int width, int height, int flags); + long windowDeleteAtom, int x, int y, int width, int height, int flags); private native void requestFocus0(long display, long windowHandle, boolean force); private static native void setTitle0(long display, long windowHandle, String title); diff --git a/src/newt/native/KDWindow.c b/src/newt/native/KDWindow.c index e6bc7952e..dc999138c 100644 --- a/src/newt/native/KDWindow.c +++ b/src/newt/native/KDWindow.c @@ -114,8 +114,10 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_kd_KDDisplay_DispatchMessages break; case KD_EVENT_WINDOW_CLOSE: { - DBG_PRINT( "event window close : src: %p\n", userData); - (*env)->CallVoidMethod(env, javaWindow, windowDestroyNotifyID); + jboolean closed; + DBG_PRINT( "event window close : src: %p .. \n", userData); + closed = (*env)->CallBooleanMethod(env, javaWindow, windowDestroyNotifyID, JNI_FALSE); + DBG_PRINT( "event window close : src: %p, closed %d\n", userData, (int)closed); } break; case KD_EVENT_WINDOWPROPERTY_CHANGE: @@ -189,7 +191,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_kd_KDWindow_initIDs windowCreatedID = (*env)->GetMethodID(env, clazz, "windowCreated", "(J)V"); sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); - windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); if (windowCreatedID == NULL || diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index 5a35973cd..64871f11d 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -705,6 +705,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_close0 DBG_PRINT( "windowClose.0 - %p,%d, destroyNotifySent %d, view %p,%d, parent %p\n", mWin, getRetainCount(mWin), destroyNotifySent, mView, getRetainCount(mView), pWin); + [mWin setUnrealized]; + if(NULL!=mView) { // cleanup view jobject javaWindowObject = [mView getJavaWindowObject]; @@ -763,6 +765,9 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacWindow_lockSurface0 (JNIEnv *env, jclass clazz, jlong window) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); + if(NO == [mWin isRealized]) { + return JNI_FALSE; + } NewtView * mView = (NewtView *) [mWin contentView]; return [mView softLock] == YES ? JNI_TRUE : JNI_FALSE; /** deadlocks, since we render independent of focus diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index aa460ea88..c0912ad3c 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -110,6 +110,7 @@ BOOL mouseVisible; BOOL mouseInside; BOOL cursorIsHidden; + BOOL realized; NSPoint lastInsideMousePosition; @public int cachedInsets[4]; // l, r, t, b @@ -125,6 +126,8 @@ isFullscreenWindow:(BOOL)isfs; - (void) release; - (void) dealloc; +- (void) setUnrealized; +- (BOOL) isRealized; - (void) updateInsets: (JNIEnv*) env; - (void) attachToParent: (NSWindow*) parent; @@ -166,5 +169,10 @@ - (void) rightMouseUp: (NSEvent*) theEvent; - (void) otherMouseDown: (NSEvent*) theEvent; - (void) otherMouseUp: (NSEvent*) theEvent; +- (void) windowDidResize: (NSNotification*) notification; +- (void) windowDidMove: (NSNotification*) notification; +- (BOOL) windowClosingImpl: (BOOL) force; +- (BOOL) windowShouldClose: (id) sender; +- (void) windowWillClose: (NSNotification*) notification; @end diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 187aec7fb..f914467af 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -337,7 +337,7 @@ static jmethodID windowRepaintID = NULL; insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V"); focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); - windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (enqueueMouseEventID && sendMouseEventID && enqueueKeyEventID && sendKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID && @@ -372,6 +372,7 @@ static jmethodID windowRepaintID = NULL; mouseVisible = YES; mouseInside = NO; cursorIsHidden = NO; + realized = YES; return res; } @@ -393,6 +394,16 @@ static jmethodID windowRepaintID = NULL; [super dealloc]; } +- (void) setUnrealized +{ + realized = NO; +} + +- (BOOL) isRealized +{ + return realized; +} + - (void) updateInsets: (JNIEnv*) env { NSView* nsview = [self contentView]; @@ -942,8 +953,19 @@ static jint mods2JavaMods(NSUInteger mods) } } +- (BOOL)windowShouldClose: (id) sender +{ + return [self windowClosingImpl: NO]; +} + - (void)windowWillClose: (NSNotification*) notification { + [self windowClosingImpl: YES]; +} + +- (BOOL) windowClosingImpl: (BOOL) force +{ + jboolean closed = JNI_FALSE; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [self cursorHide: NO]; @@ -969,17 +991,22 @@ static jint mods2JavaMods(NSUInteger mods) return; } - [view setDestroyNotifySent: true]; - (*env)->CallVoidMethod(env, javaWindowObject, windowDestroyNotifyID); + [view setDestroyNotifySent: true]; // earmark assumption of being closed + closed = (*env)->CallBooleanMethod(env, javaWindowObject, windowDestroyNotifyID, force ? JNI_TRUE : JNI_FALSE); + if(!force && !closed) { + // not closed on java side, not force -> clear flag + [view setDestroyNotifySent: false]; + } if (shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } - DBG_PRINT( "*************** windowWillClose.X: %p\n", (void *)(intptr_t)javaWindowObject); + DBG_PRINT( "*************** windowWillClose.X: %p, closed %d\n", (void *)(intptr_t)javaWindowObject, (int)closed); } else { DBG_PRINT( "*************** windowWillClose (skip)\n"); } [pool release]; + return JNI_TRUE == closed ? YES : NO ; } @end diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 97fe6f28d..6d9c04dc3 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -810,7 +810,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, // Java::DestroyWindow(wnd) _or_ window-close-button -> // WM_CLOSE -> Java::windowDestroyNotify -> W_DESTROY case WM_CLOSE: - (*env)->CallVoidMethod(env, window, windowDestroyNotifyID); + (*env)->CallBooleanMethod(env, window, windowDestroyNotifyID, JNI_FALSE); break; case WM_DESTROY: @@ -1297,7 +1297,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V"); focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); - windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZIIIIII)V"); sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 9b99aebb5..88ac0df7e 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -266,7 +266,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Display_initIDs0 focusChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "focusChanged", "(ZZ)V"); visibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChanged", "(ZZ)V"); reparentNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "reparentNotify", "(J)V"); - windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "()V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowRepaint", "(ZIIII)V"); enqueueMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "enqueueMouseEvent", "(ZIIIIII)V"); sendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEvent", "(IIIIII)V"); @@ -563,9 +563,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 break; case ClientMessage: if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom - DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X\n", + jboolean closed; + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X ..\n", (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type); - (*env)->CallVoidMethod(env, jwindow, windowDestroyNotifyID); + closed = (*env)->CallBooleanMethod(env, jwindow, windowDestroyNotifyID, JNI_FALSE); + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X, closed: %d\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type, (int)closed); // Called by Window.java: CloseWindow(); num_events = 0; // end loop in case of destroyed display } diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 9d4ff5aaa..0f93b3e76 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -730,11 +730,13 @@ static Bool WaitForReparentNotify( Display *dpy, XEvent *event, XPointer arg ) { * Signature: (JIJJIIIII)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 - (JNIEnv *env, jobject obj, jlong jdisplay, jint screen_index, jlong jparent, jlong jwindow, + (JNIEnv *env, jobject obj, jlong jdisplay, jint screen_index, + jlong jparent, jlong jwindow, jlong windowDeleteAtom, jint x, jint y, jint width, jint height, jint flags) { Display * dpy = (Display *) (intptr_t) jdisplay; Window w = (Window)jwindow; + Atom wm_delete_atom = (Atom)windowDeleteAtom; Window root = RootWindow(dpy, screen_index); Window parent = (0!=jparent)?(Window)jparent:root; XEvent event; @@ -810,6 +812,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 XReparentWindow( dpy, w, parent, x, y ); // actual reparent call // XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) w ); XSync(dpy, False); + XSetWMProtocols(dpy, w, &wm_delete_atom, 1); // windowDeleteAtom } if( TST_FLAG_CHANGE_DECORATION(flags) ) { diff --git a/src/test/jogamp/newt/WindowImplAccess.java b/src/test/jogamp/newt/WindowImplAccess.java index e8be5f68a..3387a2ae2 100644 --- a/src/test/jogamp/newt/WindowImplAccess.java +++ b/src/test/jogamp/newt/WindowImplAccess.java @@ -38,7 +38,7 @@ public class WindowImplAccess { final WindowImpl winImpl = (WindowImpl) win.getDelegatedWindow(); winImpl.runOnEDTIfAvail(true, new Runnable() { public void run() { - winImpl.windowDestroyNotify(); + winImpl.windowDestroyNotify(false); } }); } |