From c61fa44d9a2e2049fec7833990f7bb699545bd15 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 10 Oct 2015 01:47:07 +0200 Subject: Bug 1249: NEWT/X11 Visibility: Listening to more events for updated state; Adding QUIRK_BIT_VISIBILITY 1) More visibility detection on post ConfigureNotify events, since the latter may not yet contain the updated visibility state as it whould (WM bug!): - EnterNotify - LeaveNotify - Disabled - Expose - VisibilityNotify 2) Introducing quirks. Setting QUIRK_BIT_VISIBILITY to handle the issue where visibility -> false could not even be set. --- make/scripts/tests.sh | 9 +- src/newt/classes/jogamp/newt/WindowImpl.java | 154 ++++++++++++++++++++------- src/newt/native/X11Display.c | 49 +++++++-- src/newt/native/X11Window.c | 1 + 4 files changed, 165 insertions(+), 48 deletions(-) diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 60ef1e91f..62f7dc5da 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -252,7 +252,7 @@ function jrun() { #D_ARGS="-Dnewt.debug.Window -Djogl.debug.GLDrawable" #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Window.KeyEvent" #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Window.MouseEvent -Dnewt.debug.Window.KeyEvent" - #D_ARGS="-Dnewt.debug.Window" + D_ARGS="-Dnewt.debug.Window" #D_ARGS="-Dnewt.debug.Window.visibility.failure.freeze" #D_ARGS="-Xprof" #D_ARGS="-Dnativewindow.debug=all -Djogl.debug=all -Dnewt.debug=all" @@ -474,7 +474,7 @@ function testawtswt() { #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWTAnalyzeBug455 $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWTBug450 $* -testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper $* +#testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestTeapotNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl3.newt.TestGeomShader01TextureGL3NEWT $* @@ -809,8 +809,11 @@ testawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper # Bug 1249 - NEWT X11: # - setVisible(false) IconicState not listening to _NET_WM_STATE_HIDDEN; # - setVisible(true) not restoring from _NET_WM_STATE_HIDDEN -#testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows00NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $* +testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows00NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle01NEWT +#testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle02NEWT # # NEWT Parenting (w/ NEWT, AWT or SWT) diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 107851d0b..ab2cf97c6 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -149,7 +149,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private static final PointerType[] constMousePointerTypes = new PointerType[] { PointerType.Mouse }; // - // Volatile: Multithread Mutable Access + // Volatile: Multithreaded Mutable Access // private volatile long windowHandle = 0; // lifecycle critical private volatile int pixWidth = 128, pixHeight = 128; // client-area size w/o insets in pixel units, default: may be overwritten by user @@ -181,6 +181,25 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private PointerIconImpl pointerIcon = null; private LifecycleHook lifecycleHook = null; + // + // Quirks + // + + /** + * Bug 1249 and Bug 1250: Visibility issues on X11 + * + *

+ * If {@code true} fall back to traditional visibility state, + * i.e. {@code fast=true}. + *

+ */ + static final int QUIRK_BIT_VISIBILITY = 0; + /** Regular state mask */ + /* pp */ static final Bitfield quirks = Bitfield.Factory.synchronize(Bitfield.Factory.create(32)); + // // State Mask // @@ -1206,9 +1225,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } reconfigureWindowImpl(x, y, width, height, mask); } + final void setVisibleActionImpl(final boolean visible) { boolean nativeWindowCreated = false; - boolean madeVisible = false; + int madeVisible = -1; final RecursiveLock _lock = windowLock; _lock.lock(); @@ -1226,16 +1246,31 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(!isNativeValid() && visible) { if( 0 WindowImpl.this.waitForVisible(visible, false) ) { + if( !hasVisibilityQuirk ) { + quirks.set(QUIRK_BIT_VISIBILITY); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("Setting VISIBILITY QUIRK, due to setVisible("+visible+") failure"); + } + setVisibleImpl(visible /* visible */, true /* fast */, + getX(), getY(), getWidth(), getHeight()); + if( 0 <= WindowImpl.this.waitForVisible(visible, false) ) { + madeVisible = visible ? 1 : 0; + } // else: still not working .. bail out + } // else: no other remedy known .. bail out + } else { + madeVisible = visible ? 1 : 0; + } } else { stateMask.set(STATE_BIT_VISIBLE); } @@ -1267,7 +1302,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } _lock.unlock(); } - if( nativeWindowCreated || madeVisible ) { + if( nativeWindowCreated || 1==madeVisible ) { sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener } } @@ -3354,7 +3389,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // public final void sendMouseEvent(final short eventType, final int modifiers, - final int x, final int y, final short button, final float rotation) { + final int x, final int y, final short button, final float rotation) { doMouseEvent(false, false, eventType, modifiers, x, y, button, MouseEvent.getRotationXYZ(rotation, modifiers), 1f); } @@ -4685,41 +4720,57 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Accumulated actions // + /** Triggered by implementation. */ + protected final void sendMouseEventRequestFocus(final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { + sendMouseEvent(eventType, modifiers, x, y, button, rotation); + requestFocus(false /* wait */); + } /** - * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. + * Triggered by implementation's WM events to update the visibility state and send- or enqueue one mouse event * * @param defer - * @param newX - * @param newY - * @param newWidth - * @param newHeight - * @param left insets, -1 ignored - * @param right insets, -1 ignored - * @param top insets, -1 ignored - * @param bottom insets, -1 ignored - * @param focusChange -1 ignored, 0 unfocused, > 0 focused * @param visibleChange -1 ignored, 0 invisible, > 0 visible - * @param force + * @param entranceChange -1 ignored, 0 exit, > 0 enter + * @param eventType 0 ignored, > 0 [send|enqueue]MouseEvent + * @param modifiers + * @param x + * @param y + * @param button + * @param rotation */ - protected final void sizePosInsetsFocusVisibleChanged(final boolean defer, - final int newX, final int newY, - final int newWidth, final int newHeight, - final int left, final int right, final int top, final int bottom, - final int focusChange, - final int visibleChange, - final boolean force) { - sizeChanged(defer, newWidth, newHeight, force); - positionChanged(defer, newX, newY); - insetsChanged(defer, left, right, top, bottom); - if( 0 <= focusChange ) { // ignore focus < 0 - focusChanged(defer, 0 < focusChange); + protected final void visibleChangedSendMouseEvent(final boolean defer, final int visibleChange, + final short eventType, final int modifiers, + final int x, final int y, final short button, final float rotation) { + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + if( 0 < eventType ) { + if( defer ) { + enqueueMouseEvent(false /* wait */, eventType, modifiers, x, y, button, rotation); + } else { + sendMouseEvent(eventType, modifiers, x, y, button, rotation); + } } + } + /** + * Triggered by implementation's WM events to update the content + * @param defer if true sent event later, otherwise wait until processed. + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param x dirty-region y-pos in pixel units + * @param y dirty-region x-pos in pixel units + * @param width dirty-region width in pixel units + * @param height dirty-region height in pixel units + */ + protected final void visibleChangedWindowRepaint(final boolean defer, final int visibleChange, + final int x, final int y, final int width, final int height) { if( 0 <= visibleChange ) { // ignore visible < 0 visibleChanged(defer, 0 < visibleChange); } + windowRepaint(defer, x, y, width, height); } /** - * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. + * Triggered by implementation's WM events to update the focus and visibility state * * @param defer * @param focusChange -1 ignored, 0 unfocused, > 0 focused @@ -4753,6 +4804,39 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer visibleChanged(defer, 0 < visibleChange); } } + /** + * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. + * + * @param defer + * @param newX + * @param newY + * @param newWidth + * @param newHeight + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * @param focusChange -1 ignored, 0 unfocused, > 0 focused + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param force + */ + protected final void sizePosInsetsFocusVisibleChanged(final boolean defer, + final int newX, final int newY, + final int newWidth, final int newHeight, + final int left, final int right, final int top, final int bottom, + final int focusChange, + final int visibleChange, + final boolean force) { + sizeChanged(defer, newWidth, newHeight, force); + positionChanged(defer, newX, newY); + insetsChanged(defer, left, right, top, bottom); + if( 0 <= focusChange ) { // ignore focus < 0 + focusChanged(defer, 0 < focusChange); + } + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } + } /** * Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. * @@ -4787,12 +4871,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer visibleChanged(defer, 0 < visibleChange); } } - /** Triggered by implementation. */ - protected final void sendMouseEventRequestFocus(final short eventType, final int modifiers, - final int x, final int y, final short button, final float rotation) { - sendMouseEvent(eventType, modifiers, x, y, button, rotation); - requestFocus(false /* wait */); - } // // Reflection helper .. diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index ab5afd1d6..32e0f8786 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -53,6 +53,8 @@ static jmethodID windowRepaintID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID sendMouseEventRequestFocusID = NULL; +static jmethodID visibleChangedWindowRepaintID = NULL; +static jmethodID visibleChangedSendMouseEventID = NULL; static jmethodID sizePosMaxInsetsVisibleChangedID = NULL; /** @@ -260,8 +262,10 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 reparentNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "reparentNotify", "(J)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowRepaint", "(ZIIII)V"); + visibleChangedWindowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChangedWindowRepaint", "(ZIIIII)V"); sendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEvent", "(SIIISF)V"); sendMouseEventRequestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEventRequestFocus", "(SIIISF)V"); + visibleChangedSendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChangedSendMouseEvent", "(ZISIIISF)V"); sendKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendKeyEvent", "(SISSCLjava/lang/String;)V"); if (displayCompletedID == NULL || @@ -278,8 +282,10 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 reparentNotifyID == NULL || windowDestroyNotifyID == NULL || windowRepaintID == NULL || + visibleChangedWindowRepaintID == NULL || sendMouseEventID == NULL || sendMouseEventRequestFocusID == NULL || + visibleChangedSendMouseEventID == NULL || sendKeyEventID == NULL) { return JNI_FALSE; } @@ -564,15 +570,23 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage break; case EnterNotify: DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - (*env)->CallVoidMethod(env, jw->jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_ENTERED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + { + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "EnterNotify"); + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedSendMouseEventID, JNI_FALSE, (jint)visibleChange, + (jshort) EVENT_MOUSE_ENTERED, modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + } break; case LeaveNotify: DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - (*env)->CallVoidMethod(env, jw->jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_EXITED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + { + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "LeaveNotify"); + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedSendMouseEventID, JNI_FALSE, (jint)visibleChange, + (jshort) EVENT_MOUSE_EXITED, modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + } break; case MappingNotify: DBG_PRINT( "X11: event . MappingNotify call %p type %d\n", (void*)evt.xmapping.window, evt.xmapping.type); @@ -621,6 +635,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage } break; case ClientMessage: + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X, sendEvent %d\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type, evt.xclient.send_event); if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom jboolean closed; DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X ..\n", @@ -651,13 +667,32 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage } break; + case VisibilityNotify: + DBG_PRINT( "X11: event . VisibilityNotify call %p\n", (void*)evt.xvisibility.window); + { + #if 0 + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "VisibilityNotify"); + if( 0 <= visibleChange ) { + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedID, JNI_FALSE, 0 < visibleChange ? JNI_TRUE : JNI_FALSE); + } + #endif + } + break; + + case Expose: DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)evt.xexpose.window, evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.count); - if (evt.xexpose.count == 0 && evt.xexpose.width > 0 && evt.xexpose.height > 0) { (*env)->CallVoidMethod(env, jw->jwindow, windowRepaintID, JNI_FALSE, evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); + #if 0 + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange = NewtWindows_updateVisibility(env, dpy, jw, netWMState, "Expose"); + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedWindowRepaintID, JNI_FALSE, (jint)visibleChange, + evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); + #endif } break; diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index f10db317a..de2bddc86 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -848,6 +848,7 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind xswa.event_mask = X11_MOUSE_EVENT_MASK; xswa.event_mask |= KeyPressMask | KeyReleaseMask ; xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask; + // xswa.event_mask |= VisibilityChangeMask; { int _x = x, _y = y; // pos for CreateWindow, might be tweaked -- cgit v1.2.3