diff options
author | Sven Gothel <[email protected]> | 2015-10-08 20:13:12 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-10-08 20:13:12 +0200 |
commit | dca5d36370ec5eb44998bae593880e3b10cc9a4e (patch) | |
tree | 2a79a91b4a8c14dec7120c81df851e044cec014d | |
parent | 56eb5025694064ad3e25cf2fb7ba0cabbda8ee67 (diff) |
Bug 1249 - NEWT X11: setVisible(false) IconicState not listening to _NET_WM_STATE_HIDDEN; setVisible(true) not restoring from _NET_WM_STATE_HIDDEN
Using Gnome Shell 3.14.4-1~deb8u1 disclosed an issue w/ our newly utilized IconicState/_NET_WM_STATE_HIDDEN,
i.e. visibleChanged(false) was never received.
This is a regression of commit 2d837a7a7130702ad36b694875613fae77c7ef06,
which utilizes WM_CHANGE_STATE_IDX + IconicState for visibility
on top-level windows.
This bug consist out of _two_ isssue:
1) setVisible(false) IconicState not listening to _NET_WM_STATE_HIDDEN
Here, we 'listen' to _NET_WM_STATE_HIDDEN when receiving ConfigureNotify
if supported _and_ XMapWindow has been issued.
In such case existence/non-existence of _NET_WM_STATE_HIDDEN determines visibility.
Otherwise, we have wait for MapNotify/UnmapNotify.
The 'XMapWindow has been issued' criteria is tracked by new field 'JavaWindow.isMapped'
and set/cleared when we actually issue XMapWindow/XUnmapWindow!
2) setVisible(true) not restoring from _NET_WM_STATE_HIDDEN
It has been observed that restoring IconicState/_NET_WM_STATE_HIDDEN
via XMapWindow or even NormalState may not work reliably on WMs.
See <https://stackoverflow.com/questions/30192347/how-to-restore-a-window-with-xlib>
Hence we restore from this WM state via NormalState _and_ _NET_ACTIVE_WINDOW.
Both strategies seem to work well on KDE as well as on Gnome.
-rw-r--r-- | make/scripts/tests.sh | 4 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/WindowImpl.java | 93 | ||||
-rw-r--r-- | src/newt/native/WindowsWindow.c | 6 | ||||
-rw-r--r-- | src/newt/native/X11Common.h | 57 | ||||
-rw-r--r-- | src/newt/native/X11Display.c | 53 | ||||
-rw-r--r-- | src/newt/native/X11Window.c | 156 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java | 84 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java | 99 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java | 90 |
9 files changed, 416 insertions, 226 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 30164e0b8..6719b3ebf 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -427,7 +427,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile02NEWTNoARBCtx $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile03NEWTOffscreen $* #testnoawt com.jogamp.opengl.test.junit.jogl.acore.TestGLProfile04NEWTOffscreenNoARBCtx $* -testawt com.jogamp.opengl.test.junit.jogl.acore.TestVersionSemanticsNOUI $* +#testawt com.jogamp.opengl.test.junit.jogl.acore.TestVersionSemanticsNOUI $* # # Stereo @@ -637,6 +637,7 @@ testawt com.jogamp.opengl.test.junit.jogl.acore.TestVersionSemanticsNOUI $* #testnoawt com.jogamp.opengl.test.junit.newt.TestWindows02NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol02NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestWindowAndPointerIconNEWT $* +#testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows00NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows02NEWTAnimated $* #testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows03NEWTAnimResize $* @@ -806,6 +807,7 @@ testawt com.jogamp.opengl.test.junit.jogl.acore.TestVersionSemanticsNOUI $* # # NEWT Parenting (w/ NEWT, AWT or SWT) # +testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows00NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting02NEWT $* #testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01cSwingAWT $* diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index a10cd0b4e..922b75a2e 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -4557,6 +4557,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** * Triggered by implementation's WM events to update the insets. * + * @param defer + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * * @see #getInsets() * @see #updateInsetsImpl(Insets) */ @@ -4661,31 +4667,90 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Accumulated actions // - /** 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 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 boolean focusGained, - final boolean visible, + final int focusChange, + final int visibleChange, final boolean force) { sizeChanged(defer, newWidth, newHeight, force); positionChanged(defer, newX, newY); insetsChanged(defer, left, right, top, bottom); - focusChanged(defer, focusGained); - visibleChanged(defer, visible); - } - /** Triggered by implementation's WM events to update the client-area position, size, insets and maximized flags. */ - protected final void sizePosMaxInsetsChanged(final boolean defer, - final int newX, final int newY, - final int newWidth, final int newHeight, - final boolean newMaxHorz, final boolean newMaxVert, - final int left, final int right, final int top, final int bottom, - final boolean force) { + 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. + * + * @param defer + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + */ + protected final void insetsVisibleChanged(final boolean defer, + final int left, final int right, final int top, final int bottom, + final int visibleChange) { + insetsChanged(defer, left, right, top, bottom); + 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. + * + * @param defer + * @param newX + * @param newY + * @param newWidth + * @param newHeight + * @param maxHorzChange -1 ignored, 0 !maximized, > 0 maximized + * @param maxVertChange -1 ignored, 0 !maximized, > 0 maximized + * @param left insets, -1 ignored + * @param right insets, -1 ignored + * @param top insets, -1 ignored + * @param bottom insets, -1 ignored + * @param visibleChange -1 ignored, 0 invisible, > 0 visible + * @param force + */ + protected final void sizePosMaxInsetsVisibleChanged(final boolean defer, + final int newX, final int newY, + final int newWidth, final int newHeight, + final int maxHorzChange, final int maxVertChange, + final int left, final int right, final int top, final int bottom, + final int visibleChange, + final boolean force) { sizeChanged(defer, newWidth, newHeight, force); positionChanged(defer, newX, newY); - maximizedChanged(newMaxHorz, newMaxVert); + if( 0 <= maxHorzChange && 0 <= maxVertChange ) { + maximizedChanged(0 < maxHorzChange, 0 < maxVertChange); + } insetsChanged(defer, left, right, top, bottom); + if( 0 <= visibleChange ) { // ignore visible < 0 + visibleChanged(defer, 0 < visibleChange); + } } /** Triggered by implementation. */ protected final void sendMouseEventRequestFocus(final short eventType, final int modifiers, diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 882559551..59e054516 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -2128,7 +2128,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V"); focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); - sizePosInsetsFocusVisibleChangedID = (*env)->GetMethodID(env, clazz, "sizePosInsetsFocusVisibleChanged", "(ZIIIIIIIIZZZ)V"); + sizePosInsetsFocusVisibleChangedID = (*env)->GetMethodID(env, clazz, "sizePosInsetsFocusVisibleChanged", "(ZIIIIIIIIIIZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(SIIISF)V"); @@ -2414,8 +2414,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_InitWindow0 (jint)wud->xpos, (jint)wud->ypos, (jint)wud->width, (jint)wud->height, (jint)wud->insets.left, (jint)wud->insets.right, (jint)wud->insets.top, (jint)wud->insets.bottom, - (jboolean)wud->focused, - (jboolean)wud->visible, + (jint)(wud->focused ? 1 : 0), + (jint)(wud->visible ? 1 : 0), JNI_FALSE); DBG_PRINT("*** WindowsWindow: InitWindow JNI callbacks done\n"); diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h index cdfb65d50..e46996441 100644 --- a/src/newt/native/X11Common.h +++ b/src/newt/native/X11Common.h @@ -71,7 +71,7 @@ extern jclass X11NewtWindowClazz; extern jmethodID insetsChangedID; extern jmethodID visibleChangedID; -extern jmethodID sizePosMaxInsetsChanged; +extern jmethodID insetsVisibleChangedID; typedef struct { Window window; @@ -83,13 +83,66 @@ typedef struct { uint32_t lastDesktop; Bool maxHorz; Bool maxVert; + Bool isMapped; } JavaWindow; JavaWindow * getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); Bool NewtWindows_updateInsets(Display *dpy, JavaWindow * w, int *left, int *right, int *top, int *bottom); -Bool NewtWindows_updateMaximized(Display *dpy, JavaWindow * w); +Bool NewtWindows_updateMaximized(Display *dpy, JavaWindow * w, uint32_t netWMState); + +#define _MASK_NET_WM_STATE ( 1 << 0 ) +#define _MASK_NET_WM_STATE_MODAL ( 1 << 1 ) +#define _MASK_NET_WM_STATE_STICKY ( 1 << 2 ) +#define _MASK_NET_WM_STATE_MAXIMIZED_VERT ( 1 << 3 ) +#define _MASK_NET_WM_STATE_MAXIMIZED_HORZ ( 1 << 4 ) +#define _MASK_NET_WM_STATE_SHADED ( 1 << 5 ) +#define _MASK_NET_WM_STATE_HIDDEN ( 1 << 8 ) +#define _MASK_NET_WM_STATE_FULLSCREEN ( 1 << 9 ) +#define _MASK_NET_WM_STATE_ABOVE ( 1 << 10 ) +#define _MASK_NET_WM_STATE_BELOW ( 1 << 11 ) +#define _MASK_NET_WM_STATE_DEMANDS_ATTENTION ( 1 << 12 ) +#define _MASK_NET_WM_STATE_FOCUSED ( 1 << 13 ) +#define _MASK_NET_WM_BYPASS_COMPOSITOR ( 1 << 14 ) +#define _MASK_NET_WM_DESKTOP ( 1 << 15 ) +#define _MASK_NET_CURRENT_DESKTOP ( 1 << 16 ) +#define _MASK_NET_WM_WINDOW_TYPE ( 1 << 17 ) +#define _MASK_NET_WM_WINDOW_TYPE_NORMAL ( 1 << 18 ) +#define _MASK_NET_WM_WINDOW_TYPE_POPUP_MENU ( 1 << 19 ) +#define _MASK_NET_FRAME_EXTENTS ( 1 << 20 ) +#define _MASK_NET_SUPPORTED ( 1 << 21 ) +#define _MASK_NET_ACTIVE_WINDOW ( 1 << 22 ) +#define _MASK_WM_CHANGE_STATE ( 1 << 23 ) +#define _MASK_MOTIF_WM_HINTS ( 1 << 24 ) + +#define _NET_WM_STATE_IDX 0 +#define _NET_WM_STATE_MODAL_IDX 1 +#define _NET_WM_STATE_STICKY_IDX 2 +#define _NET_WM_STATE_MAXIMIZED_VERT_IDX 3 +#define _NET_WM_STATE_MAXIMIZED_HORZ_IDX 4 +#define _NET_WM_STATE_SHADED_IDX 5 +#define _NET_WM_STATE_SKIP_TASKBAR_IDX 6 +#define _NET_WM_STATE_SKIP_PAGER_IDX 7 +#define _NET_WM_STATE_HIDDEN_IDX 8 +#define _NET_WM_STATE_FULLSCREEN_IDX 9 +#define _NET_WM_STATE_ABOVE_IDX 10 +#define _NET_WM_STATE_BELOW_IDX 11 +#define _NET_WM_STATE_DEMANDS_ATTENTION_IDX 12 +#define _NET_WM_STATE_FOCUSED_IDX 13 +#define _NET_WM_BYPASS_COMPOSITOR_IDX 14 +#define _NET_WM_DESKTOP_IDX 15 +#define _NET_CURRENT_DESKTOP_IDX 16 +#define _NET_WM_WINDOW_TYPE_IDX 17 +#define _NET_WM_WINDOW_TYPE_NORMAL_IDX 18 +#define _NET_WM_WINDOW_TYPE_POPUP_MENU_IDX 19 +#define _NET_FRAME_EXTENTS_IDX 20 +#define _NET_SUPPORTED_IDX 21 +#define _NET_ACTIVE_WINDOW_IDX 22 +#define _WM_CHANGE_STATE_IDX 23 +#define _MOTIF_WM_HINTS_IDX 24 + +uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, JavaWindow *w); #endif /* _X11COMMON_H_ */ diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 7ac6e8639..b3373827a 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -35,7 +35,7 @@ jclass X11NewtWindowClazz = NULL; jmethodID insetsChangedID = NULL; jmethodID visibleChangedID = NULL; -jmethodID sizePosMaxInsetsChangedID = NULL; +jmethodID insetsVisibleChangedID = NULL; static const char * const ClazzNameX11NewtWindow = "jogamp/newt/driver/x11/WindowDriver"; @@ -53,6 +53,7 @@ static jmethodID windowRepaintID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID sendMouseEventRequestFocusID = NULL; +static jmethodID sizePosMaxInsetsVisibleChangedID = NULL; /** * Keycode @@ -254,7 +255,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 positionChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "positionChanged", "(ZII)V"); focusChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "focusChanged", "(ZZ)V"); visibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChanged", "(ZZ)V"); - sizePosMaxInsetsChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sizePosMaxInsetsChanged", "(ZIIIIZZIIIIZ)V"); + insetsVisibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "insetsVisibleChanged", "(ZIIIII)V"); + sizePosMaxInsetsVisibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sizePosMaxInsetsVisibleChanged", "(ZIIIIIIIIIIIZ)V"); reparentNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "reparentNotify", "(J)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowRepaint", "(ZIIII)V"); @@ -271,7 +273,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 positionChangedID == NULL || focusChangedID == NULL || visibleChangedID == NULL || - sizePosMaxInsetsChangedID == NULL || + insetsVisibleChangedID == NULL || + sizePosMaxInsetsVisibleChangedID == NULL || reparentNotifyID == NULL || windowDestroyNotifyID == NULL || windowRepaintID == NULL || @@ -578,15 +581,38 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event); if ( evt.xconfigure.window == evt.xconfigure.event ) { // ignore child window change notification - // update insets + // insets: negative values are ignored int left=-1, right=-1, top=-1, bottom=-1; + uint32_t netWMState = NewtWindows_getNET_WM_STATE(dpy, jw); + int visibleChange; + if( jw->isMapped && 0 != ( _MASK_NET_WM_STATE_HIDDEN & jw->supportedAtoms ) ) { + if( 0 != ( _MASK_NET_WM_STATE_HIDDEN & netWMState ) ) { + visibleChange = 0; + } else { + visibleChange = 1; + } + } else { + visibleChange = -1; + } + #ifdef VERBOSE_ON + XWindowAttributes xwa; + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, jw->window, &xwa); + + // map_state: IsUnmapped(0), IsUnviewable(1), IsViewable(2) + DBG_PRINT( "X11: event . ConfigureNotify call %p - isMapped %d, visibleChanged %d, map_state %d\n", + (void*)evt.xconfigure.window, jw->isMapped, visibleChange, xwa.map_state); + #endif + NewtWindows_updateInsets(dpy, jw, &left, &right, &top, &bottom); - NewtWindows_updateMaximized(dpy, jw); - (*env)->CallVoidMethod(env, jw->jwindow, sizePosMaxInsetsChangedID, JNI_FALSE, + Bool maxChanged = NewtWindows_updateMaximized(dpy, jw, netWMState); + (*env)->CallVoidMethod(env, jw->jwindow, sizePosMaxInsetsVisibleChangedID, JNI_FALSE, (jint) evt.xconfigure.x, (jint) evt.xconfigure.y, (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, - (jboolean)jw->maxHorz, (jboolean)jw->maxVert, + (jint)(maxChanged ? ( jw->maxHorz ? 1 : 0 ) : -1), + (jint)(maxChanged ? ( jw->maxVert ? 1 : 0 ) : -1), (jint)left, (jint)right, (jint)top, (jint)bottom, + (jint)visibleChange, JNI_FALSE); } break; @@ -629,14 +655,13 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage evt.xmap.event!=evt.xmap.window); if( evt.xmap.event == evt.xmap.window ) { // ignore child window notification - { - // update insets - int left, right, top, bottom; - if( NewtWindows_updateInsets(dpy, jw, &left, &right, &top, &bottom) ) { - (*env)->CallVoidMethod(env, jw->jwindow, insetsChangedID, JNI_FALSE, left, right, top, bottom); - } + // insets: negative values are ignored + int left=-1, right=-1, top=-1, bottom=-1; + if( NewtWindows_updateInsets(dpy, jw, &left, &right, &top, &bottom) ) { + (*env)->CallVoidMethod(env, jw->jwindow, insetsVisibleChangedID, JNI_FALSE, left, right, top, bottom, 1); + } else { + (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); } - (*env)->CallVoidMethod(env, jw->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); } break; diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index c798af8e9..26029801b 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -85,53 +85,7 @@ static uintptr_t getPtrOut32Long(unsigned long * src) { #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 -#define _MASK_NET_WM_STATE ( 1 << 0 ) -#define _MASK_NET_WM_STATE_MODAL ( 1 << 1 ) -#define _MASK_NET_WM_STATE_STICKY ( 1 << 2 ) -#define _MASK_NET_WM_STATE_MAXIMIZED_VERT ( 1 << 3 ) -#define _MASK_NET_WM_STATE_MAXIMIZED_HORZ ( 1 << 4 ) -#define _MASK_NET_WM_STATE_SHADED ( 1 << 5 ) -#define _MASK_NET_WM_STATE_HIDDEN ( 1 << 8 ) -#define _MASK_NET_WM_STATE_FULLSCREEN ( 1 << 9 ) -#define _MASK_NET_WM_STATE_ABOVE ( 1 << 10 ) -#define _MASK_NET_WM_STATE_BELOW ( 1 << 11 ) -#define _MASK_NET_WM_STATE_DEMANDS_ATTENTION ( 1 << 12 ) -#define _MASK_NET_WM_STATE_FOCUSED ( 1 << 13 ) -#define _MASK_NET_WM_BYPASS_COMPOSITOR ( 1 << 14 ) -#define _MASK_NET_WM_DESKTOP ( 1 << 15 ) -#define _MASK_NET_CURRENT_DESKTOP ( 1 << 16 ) -#define _MASK_NET_WM_WINDOW_TYPE ( 1 << 17 ) -#define _MASK_NET_WM_WINDOW_TYPE_NORMAL ( 1 << 18 ) -#define _MASK_NET_WM_WINDOW_TYPE_POPUP_MENU ( 1 << 19 ) -#define _MASK_NET_FRAME_EXTENTS ( 1 << 20 ) -#define _MASK_NET_SUPPORTED ( 1 << 21 ) -#define _MASK_WM_CHANGE_STATE ( 1 << 22 ) -#define _MASK_MOTIF_WM_HINTS ( 1 << 23 ) - -#define _NET_WM_STATE_IDX 0 -#define _NET_WM_STATE_MODAL_IDX 1 -#define _NET_WM_STATE_STICKY_IDX 2 -#define _NET_WM_STATE_MAXIMIZED_VERT_IDX 3 -#define _NET_WM_STATE_MAXIMIZED_HORZ_IDX 4 -#define _NET_WM_STATE_SHADED_IDX 5 -#define _NET_WM_STATE_SKIP_TASKBAR_IDX 6 -#define _NET_WM_STATE_SKIP_PAGER_IDX 7 -#define _NET_WM_STATE_HIDDEN_IDX 8 -#define _NET_WM_STATE_FULLSCREEN_IDX 9 -#define _NET_WM_STATE_ABOVE_IDX 10 -#define _NET_WM_STATE_BELOW_IDX 11 -#define _NET_WM_STATE_DEMANDS_ATTENTION_IDX 12 -#define _NET_WM_STATE_FOCUSED_IDX 13 -#define _NET_WM_BYPASS_COMPOSITOR_IDX 14 -#define _NET_WM_DESKTOP_IDX 15 -#define _NET_CURRENT_DESKTOP_IDX 16 -#define _NET_WM_WINDOW_TYPE_IDX 17 -#define _NET_WM_WINDOW_TYPE_NORMAL_IDX 18 -#define _NET_WM_WINDOW_TYPE_POPUP_MENU_IDX 19 -#define _NET_FRAME_EXTENTS_IDX 20 -#define _NET_SUPPORTED_IDX 21 -#define _WM_CHANGE_STATE_IDX 22 -#define _MOTIF_WM_HINTS_IDX 23 +/** Sync w/ X11Common.h MASK and IDX */ static const char * _ALL_ATOM_NAMES[] = { /* 0 */ "_NET_WM_STATE", /* 1 */ "_NET_WM_STATE_MODAL", @@ -155,8 +109,9 @@ static const char * _ALL_ATOM_NAMES[] = { /* 19 */ "_NET_WM_WINDOW_TYPE_POPUP_MENU", /* 20 */ "_NET_FRAME_EXTENTS", /* 21 */ "_NET_SUPPORTED", - /* 22 */ "WM_CHANGE_STATE", - /* 23 */ "_MOTIF_WM_HINTS" + /* 22 */ "_NET_ACTIVE_WINDOW", + /* 23 */ "WM_CHANGE_STATE", + /* 24 */ "_MOTIF_WM_HINTS" }; static const uint32_t _ALL_ATOM_COUNT = (uint32_t)(sizeof(_ALL_ATOM_NAMES)/sizeof(const char *)); @@ -185,7 +140,6 @@ static uint32_t NewtWindows_getSupportedFeaturesEWMH(Display *dpy, Window root, uint32_t res = 0; Status s; - XSync(dpy, False); if ( Success == (s = XGetWindowProperty(dpy, root, allAtoms[_NET_SUPPORTED_IDX], 0, 1024, False, AnyPropertyType, &type, &form, &props_count, &remain, (unsigned char**)&properties)) ) { if( NULL != properties ) { @@ -202,7 +156,16 @@ static uint32_t NewtWindows_getSupportedFeaturesEWMH(Display *dpy, Window root, } return res; } -static uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, Window window, Atom * allAtoms, Bool verbose) { +uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, JavaWindow *w) { + Bool verbose = +#ifdef VERBOSE_ON + True +#else + False +#endif + ; + Window window = w->window; + Atom * allAtoms = w->allAtoms; Atom * properties = NULL; Atom type = 0; unsigned long props_count = 0, remain = 0; @@ -210,7 +173,6 @@ static uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, Window window, Atom * uint32_t res = 0; Status s; - XSync(dpy, False); if ( Success == (s = XGetWindowProperty(dpy, window, allAtoms[_NET_WM_STATE_IDX], 0, 1024, False, AnyPropertyType, &type, &form, &props_count, &remain, (unsigned char**)&properties)) ) { if( NULL != properties ) { @@ -220,7 +182,7 @@ static uint32_t NewtWindows_getNET_WM_STATE(Display *dpy, Window window, Atom * XFree(properties); } if(verbose) { - fprintf(stderr, "**************** X11: WM_STATE of %p: 0x%X\n", (void*)window, res); + fprintf(stderr, "**************** X11: WM_STATE of %p: %d props -> 0x%X\n", (void*)window, (int)props_count, res); } } else if(verbose) { fprintf(stderr, "**************** X11: WM_STATE of %p: XGetWindowProperty failed: %d\n", (void*)window, s); @@ -249,6 +211,7 @@ static JavaWindow* createJavaWindowProperty(JNIEnv *env, Display *dpy, Window ro res->lastDesktop = 0; //undef res->maxHorz = False; res->maxVert = False; + res->isMapped=False; } unsigned long jogl_java_object_data[2]; // X11 is based on 'unsigned long' int nitems_32 = putPtrIn32Long( jogl_java_object_data, (uintptr_t) res); @@ -352,7 +315,6 @@ static void NewtWindows_setCWAbove(Display *dpy, Window w) { memset(&xwc, 0, sizeof(XWindowChanges)); xwc.stack_mode = Above; XConfigureWindow(dpy, w, CWStackMode, &xwc); - XSync(dpy, False); } static Status NewtWindows_getWindowPositionRelative2Parent (Display *dpy, Window w, int *x_return, int *y_return) { Window root_return; @@ -440,8 +402,7 @@ static void NewtWindows_setDecorations (Display *dpy, JavaWindow *w, Bool decora #ifdef DECOR_USE_EWMH XChangeProperty( dpy, w->window, w->allAtoms[_NET_WM_WINDOW_TYPE_IDX], XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); #endif - - XSync(dpy, False); + XFlush(dpy); } static Bool NewtWindows_hasDecorations (Display *dpy, JavaWindow * w) { @@ -473,7 +434,6 @@ static void NewtWindows_requestFocus (Display *dpy, JavaWindow * jw, Bool force) Window focus_return; int revert_to_return; - XSync(dpy, False); XGetInputFocus(dpy, &focus_return, &revert_to_return); DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d, hasFocus %d\n", dpy, (void*)jw->window, force, focus_return==jw->window); @@ -488,8 +448,8 @@ static void NewtWindows_requestFocus (Display *dpy, JavaWindow * jw, Bool force) XSetInputFocus(dpy, jw->window, RevertToParent, CurrentTime); } } + XFlush(dpy); DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d - FIN\n", dpy, (void*)jw->window, force); - XSync(dpy, False); } Bool NewtWindows_updateInsets(Display *dpy, JavaWindow * w, int *left, int *right, int *top, int *bottom) { @@ -513,16 +473,9 @@ Bool NewtWindows_updateInsets(Display *dpy, JavaWindow * w, int *left, int *righ return False; // Error } -Bool NewtWindows_updateMaximized(Display *dpy, JavaWindow * w) { - uint32_t state = NewtWindows_getNET_WM_STATE(dpy, w->window, w->allAtoms, -#ifdef VERBOSE_ON - True -#else - False -#endif - ); - Bool maxHorz = 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_HORZ & state ) ; - Bool maxVert = 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_VERT & state ) ; +Bool NewtWindows_updateMaximized(Display *dpy, JavaWindow * w, uint32_t netWMState) { + Bool maxHorz = 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_HORZ & netWMState ) ; + Bool maxVert = 0 != ( _MASK_NET_WM_STATE_MAXIMIZED_VERT & netWMState ) ; if( w->maxHorz != maxHorz || w->maxVert != maxVert ) { w->maxHorz = maxHorz; w->maxVert = maxVert; @@ -558,7 +511,7 @@ static void NewtWindows_setWindowTypeEWMH (Display *dpy, JavaWindow * w, int typ } // else { } if( 0 != types[0] ) { XChangeProperty( dpy, w->window, w->allAtoms[_NET_WM_WINDOW_TYPE_IDX], XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1); - XSync(dpy, False); + XFlush(dpy); } } @@ -694,7 +647,7 @@ static void NewtWindows_setStackingEWMHFlags (Display *dpy, Window root, JavaWin changeMaxVert ? _NET_WM_STATE_MAXIMIZED_VERT_IDX : 0, enable); } - XSync(dpy, False); + XFlush(dpy); DBG_PRINT( "X11: setStackingEWMHFlags ON %d, change[Sticky %d, Fullscreen %d, Above %d, Below %d, MaxV %d, MaxH %d]\n", enable, changeSticky, changeFullscreen, changeAbove, changeBelow, changeMaxVert, changeMaxHorz); } @@ -709,35 +662,49 @@ static Bool WaitForUnmapNotify( Display *dpy, XEvent *event, XPointer arg ) { static void NewtWindows_setVisible(Display *dpy, Window root, JavaWindow* jw, Bool visible, Bool useWM, Bool waitForNotify) { XEvent event; - if( !visible && useWM && 0 != ( _MASK_NET_WM_STATE_HIDDEN & jw->supportedAtoms ) ) { - DBG_PRINT( "X11: setVisible -> %d, method: IconicState, wait %d, window %p\n", (int)visible, (int)waitForNotify, (void*)jw->window); - // It has been experienced that UnmapNotify is not sent for child windows when using IconicState! + DBG_PRINT( "X11: setVisible -> %d, useWM: %d, wait %d, window %p\n", (int)visible, (int)useWM, (int)waitForNotify, (void*)jw->window); + if( useWM && jw->isMapped && 0 != ( _MASK_NET_WM_STATE_HIDDEN & jw->supportedAtoms ) ) { + // It has been experienced that MapNotify/UnmapNotify is not sent for windows when using NormalState/IconicState! + // See X11Display.c::Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0 case ConfigureNotify XEvent xev; memset ( &xev, 0, sizeof(xev) ); xev.type = ClientMessage; xev.xclient.window = jw->window; xev.xclient.message_type = jw->allAtoms[_WM_CHANGE_STATE_IDX]; xev.xclient.format = 32; - xev.xclient.data.l[0] = IconicState; + if( visible ) { + xev.xclient.data.l[0] = NormalState; + } else { + xev.xclient.data.l[0] = IconicState; + } XSendEvent ( dpy, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xev ); - // NewtWindows_sendNET_WM_STATE(dpy, root, jw, _NET_WM_STATE_HIDDEN_IDX, 0, !visible); - if(waitForNotify) { - XIfEvent( dpy, &event, WaitForUnmapNotify, (XPointer) jw->window ); + if( visible ) { + // NormalState may not work on some WMs (Gnome, KDE) ? + memset ( &xev, 0, sizeof(xev) ); + xev.type = ClientMessage; + xev.xclient.window = jw->window; + xev.xclient.message_type = jw->allAtoms[_NET_ACTIVE_WINDOW_IDX]; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; //source indication for normal applications + xev.xclient.data.l[1] = CurrentTime; + XSendEvent ( dpy, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xev ); } } else { - DBG_PRINT( "X11: setVisible -> %d, method: Map/Unmap, wait %d, window %p\n", (int)visible, (int)waitForNotify, (void*)jw->window); if( visible ) { XMapRaised(dpy, jw->window); if(waitForNotify) { XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) jw->window ); } + jw->isMapped=True; } else { XUnmapWindow(dpy, jw->window); if(waitForNotify) { XIfEvent( dpy, &event, WaitForUnmapNotify, (XPointer) jw->window ); } + jw->isMapped=False; } } + XFlush(dpy); } @@ -771,7 +738,7 @@ static void NewtWindows_setPosSize(Display *dpy, JavaWindow* w, jint x, jint y, xwc.height=height; } XConfigureWindow(dpy, w->window, flags, &xwc); - XSync(dpy, False); + XFlush(dpy); } } @@ -910,7 +877,8 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind // we can pre-map the window here to be able to gather the insets and position. { XEvent event; - int left=0, right=0, top=0, bottom=0; + // insets: negative values are ignored + int left=-1, right=-1, top=-1, bottom=-1; const unsigned char * pixelPtr = NULL; // NOTE: MUST BE DIRECT BUFFER, since _NET_WM_ICON Atom uses buffer directly! @@ -925,18 +893,20 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind XMapWindow(dpy, window); XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) window ); // wait to get proper insets values - - XSync(dpy, False); + javaWindow->isMapped=True; if( JNI_FALSE == pixels_is_direct && NULL != pixelPtr ) { (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); } // send insets before visibility, allowing java code a proper sync point! + XSync(dpy, False); if( NewtWindows_updateInsets(dpy, javaWindow, &left, &right, &top, &bottom) ) { - (*env)->CallVoidMethod(env, javaWindow->jwindow, insetsChangedID, JNI_FALSE, left, right, top, bottom); + (*env)->CallVoidMethod(env, javaWindow->jwindow, insetsVisibleChangedID, JNI_FALSE, left, right, top, bottom, 1); + } else { + (*env)->CallVoidMethod(env, javaWindow->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); + left=0; right=0; top=0; bottom=0; } - (*env)->CallVoidMethod(env, javaWindow->jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); if( TST_FLAG_IS_AUTOPOSITION(flags) ) { // get position from WM @@ -974,6 +944,7 @@ JNIEXPORT jlongArray JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWind NewtWindows_setMinMaxSize(dpy, javaWindow, width, height, width, height); } } + XFlush(dpy); handles[0] = (jlong)(intptr_t)window; handles[1] = (jlong)(intptr_t)javaWindow; jhandles = (*env)->NewLongArray(env, 2); @@ -1053,6 +1024,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 XGetWindowAttributes(dpy, jw->window, &xwa); // prefetch colormap to be destroyed after window destruction XSelectInput(dpy, jw->window, 0); XUnmapWindow(dpy, jw->window); + jw->isMapped=False; // Drain all events related to this window .. Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, @@ -1148,6 +1120,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo TST_FLAG_CHANGE_STICKY(flags), TST_FLAG_IS_STICKY(flags), fsEWMHFlags); + XSync(dpy, False); + // FS Note: To toggle FS, utilizing the _NET_WM_STATE_FULLSCREEN WM state should be enough. // However, we have to consider other cases like reparenting and WM which don't support it. #if 0 // Also doesn't work work properly w/ Unity WM @@ -1189,8 +1163,9 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo XReparentWindow( dpy, jw->window, parent, x, y ); // actual reparent call #ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) jw->window ); + #else + XSync(dpy, False); #endif - XSync(dpy, False); XSetWMProtocols(dpy, jw->window, &wm_delete_atom, 1); // windowDeleteAtom // Fix for Unity WM, i.e. _remove_ persistent previous states NewtWindows_setStackingEWMHFlags(dpy, root, jw, fsEWMHFlags, False); @@ -1232,10 +1207,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo // CHILD: out -> in DBG_PRINT( "X11: reconfigureWindow0 PARENTING out->in\n"); XReparentWindow( dpy, jw->window, parent, x, y ); // actual reparent call + XFlush(dpy); #ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) jw->window ); + #else + XSync(dpy, False); #endif - XSync(dpy, False); } if( tempInvisible ) { @@ -1247,7 +1224,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo if( TST_FLAG_IS_VISIBLE(flags) ) { DBG_PRINT( "X11: reconfigureWindow0 VISIBLE ON\n"); NewtWindows_setVisible(dpy, root, jw, True /* visible */, useWM, False /* wait */); - XSync(dpy, False); if( !TST_FLAG_IS_MAXIMIZED_ANY(flags) ) { // WM may disregard pos/size XConfigureWindow requests for invisible windows! DBG_PRINT( "X11: reconfigureWindow0 setPosSize.2 %d/%d %dx%d\n", x, y, width, height); @@ -1256,7 +1232,6 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo } else { DBG_PRINT( "X11: reconfigureWindow0 VISIBLE OFF\n"); NewtWindows_setVisible(dpy, root, jw, False /* visible */, useWM, False /* wait */); - XSync(dpy, False); } } @@ -1277,6 +1252,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo NewtWindows_setMinMaxSize(dpy, jw, -1, -1, -1, -1); // FIXME: .. } } + XFlush(dpy); DBG_PRINT( "X11: reconfigureWindow0 X (full)\n"); } @@ -1288,7 +1264,9 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_requestFocus0 (JNIEnv *env, jclass clazz, jlong display, jlong javaWindow, jboolean force) { - NewtWindows_requestFocus ( (Display *) (intptr_t) display, (JavaWindow*)(intptr_t)javaWindow, JNI_TRUE==force?True:False ) ; + Display * dpy = (Display *) (intptr_t) display; + XSync(dpy, False); + NewtWindows_requestFocus ( dpy, (JavaWindow*)(intptr_t)javaWindow, JNI_TRUE==force?True:False ) ; } /* diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java index 9dd96acdd..8f1cdaae0 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java @@ -58,7 +58,7 @@ public class TestGLWindows00NEWT extends UITestCase { glp = GLProfile.getDefault(); } - static GLWindow createWindow(final Screen screen, final GLCapabilitiesImmutable caps) + static GLWindow createWindow(final Screen screen, final GLCapabilitiesImmutable caps, final boolean undecor) throws InterruptedException { Assert.assertNotNull(caps); @@ -78,7 +78,9 @@ public class TestGLWindows00NEWT extends UITestCase { final GLEventListener demo = new GearsES2(); glWindow.addGLEventListener(demo); + glWindow.setUndecorated(undecor); glWindow.setSize(512, 512); + System.err.println("XXX VISIBLE.0 -> TRUE"); glWindow.setVisible(true); Assert.assertEquals(true,glWindow.isVisible()); Assert.assertEquals(true,glWindow.isNativeValid()); @@ -90,25 +92,93 @@ public class TestGLWindows00NEWT extends UITestCase { if(null!=glWindow) { glWindow.destroy(); Assert.assertEquals(false,glWindow.isNativeValid()); + Assert.assertEquals(false,glWindow.isVisible()); } } @Test - public void testWindow00() throws InterruptedException { + public void test01WindowCreateSimple() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); - final GLWindow window1 = createWindow(null, caps); // local - Assert.assertEquals(true,window1.isNativeValid()); - Assert.assertEquals(true,window1.isVisible()); - final AbstractGraphicsDevice device1 = window1.getScreen().getDisplay().getGraphicsDevice(); + final GLWindow window = createWindow(null, caps, false /* undecor */); // local + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + final AbstractGraphicsDevice device1 = window.getScreen().getDisplay().getGraphicsDevice(); System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1)); for(int state=0; state*100<durationPerTest; state++) { Thread.sleep(100); } - destroyWindow(window1); + destroyWindow(window); + } + + @Test + public void test02WindowCreateUndecor() throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, true /* undecor */); // local + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + final AbstractGraphicsDevice device1 = window.getScreen().getDisplay().getGraphicsDevice(); + System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1)); + + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + destroyWindow(window); + } + + @Test + public void test10WindowSimpleToggleVisibility() throws InterruptedException { + test1xWindowToggleVisibility(false /* undecor */); + } + @Test + public void test10WindowUndecorToggleVisibility() throws InterruptedException { + test1xWindowToggleVisibility(true /* undecor */); + } + private void test1xWindowToggleVisibility(final boolean undecor) throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, undecor); // local + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + window.display(); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + System.err.println("XXX VISIBLE.1 -> FALSE"); + window.setVisible(false); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + window.display(); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + + System.err.println("XXX VISIBLE.2 -> TRUE"); + window.setVisible(true); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + window.display(); + Assert.assertEquals(true,window.isNativeValid()); + Assert.assertEquals(true,window.isVisible()); + + destroyWindow(window); } static int atoi(final String a) { diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java index ab8304504..00b31f400 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java @@ -59,8 +59,7 @@ public class TestGLWindows01NEWT extends UITestCase { } static GLWindow createWindow(final Screen screen, final GLCapabilities caps, - final int width, final int height, final boolean onscreen, final boolean undecorated, - final boolean addGLEventListenerAfterVisible) + final int width, final int height, final boolean onscreen, final boolean addGLEventListenerAfterVisible) throws InterruptedException { Assert.assertNotNull(caps); @@ -79,7 +78,6 @@ public class TestGLWindows01NEWT extends UITestCase { Assert.assertNotNull(glWindow); } - glWindow.setUndecorated(onscreen && undecorated); Assert.assertEquals(false,glWindow.isVisible()); Assert.assertEquals(false,glWindow.isNativeValid()); @@ -122,16 +120,47 @@ public class TestGLWindows01NEWT extends UITestCase { if(null!=glWindow) { glWindow.destroy(); Assert.assertEquals(false,glWindow.isNativeValid()); + Assert.assertEquals(false,glWindow.isVisible()); } } + + @Test + public void test01WindowSimple() throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, width, height, + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); + System.out.println("Created: "+window); + int state; + for(state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + System.out.println("duration: "+window.getTotalFPSDuration()); + destroyWindow(window); + } + + @Test + public void test02WindowSimple() throws InterruptedException { + final GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + final GLWindow window = createWindow(null, caps, width, height, + true /* onscreen */, true /*addGLEventListenerAfterVisible*/); + System.out.println("Created: "+window); + int state; + for(state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + System.out.println("duration: "+window.getTotalFPSDuration()); + destroyWindow(window); + } + @Test - public void testWindowNativeRecreate01aSimple() throws InterruptedException { + public void test10WindowNativeRecreateSimple() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertEquals(true,window.isNativeValid()); Assert.assertEquals(true,window.isVisible()); @@ -155,12 +184,11 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowNativeRecreate01bSimple() throws InterruptedException { + public void test11WindowNativeRecreateSimple() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - true /*addGLEventListenerAfterVisible*/); + true /* onscreen */, true /*addGLEventListenerAfterVisible*/); Assert.assertEquals(true,window.isNativeValid()); Assert.assertEquals(true,window.isVisible()); @@ -184,44 +212,11 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowDecor01aSimple() throws InterruptedException { - final GLCapabilities caps = new GLCapabilities(glp); - Assert.assertNotNull(caps); - final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); - System.out.println("Created: "+window); - int state; - for(state=0; state*100<durationPerTest; state++) { - Thread.sleep(100); - } - System.out.println("duration: "+window.getTotalFPSDuration()); - destroyWindow(window); - } - - @Test - public void testWindowDecor01bSimple() throws InterruptedException { - final GLCapabilities caps = new GLCapabilities(glp); - Assert.assertNotNull(caps); - final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - true /*addGLEventListenerAfterVisible*/); - System.out.println("Created: "+window); - int state; - for(state=0; state*100<durationPerTest; state++) { - Thread.sleep(100); - } - System.out.println("duration: "+window.getTotalFPSDuration()); - destroyWindow(window); - } - - @Test - public void testWindowDecor02DestroyWinTwiceA() throws InterruptedException { + public void test21WindowDestroyWinTwiceA() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); final GLWindow window = createWindow(null, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); int state; for(state=0; state*100<durationPerTest; state++) { Thread.sleep(100); @@ -231,7 +226,7 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowDecor03TwoWinOneDisplay() throws InterruptedException { + public void test22WindowTwoWinOneDisplay() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); @@ -241,13 +236,11 @@ public class TestGLWindows01NEWT extends UITestCase { final Screen screen = NewtFactory.createScreen(display, 0); // screen 0 Assert.assertNotNull(screen); final GLWindow window1 = createWindow(screen, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window1); final GLWindow window2 = createWindow(screen, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window2); Assert.assertEquals(1,Display.getActiveDisplayNumber()); @@ -281,7 +274,7 @@ public class TestGLWindows01NEWT extends UITestCase { } @Test - public void testWindowDecor03TwoWinTwoDisplays() throws InterruptedException { + public void test23WindowTwoWinTwoDisplays() throws InterruptedException { final GLCapabilities caps = new GLCapabilities(glp); Assert.assertNotNull(caps); @@ -294,15 +287,13 @@ public class TestGLWindows01NEWT extends UITestCase { final Screen screen1 = NewtFactory.createScreen(display1, 0); // screen 0 Assert.assertNotNull(screen1); final GLWindow window1 = createWindow(screen1, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window1); final Screen screen2 = NewtFactory.createScreen(display2, 0); // screen 0 Assert.assertNotNull(screen2); final GLWindow window2 = createWindow(screen2, caps, width, height, - true /* onscreen */, false /* undecorated */, - false /*addGLEventListenerAfterVisible*/); + true /* onscreen */, false /*addGLEventListenerAfterVisible*/); Assert.assertNotNull(window2); Assert.assertEquals(2,Display.getActiveDisplayNumber()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java index 591ce5f4e..86614c3c3 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java @@ -51,7 +51,6 @@ import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; public class TestParenting01NEWT extends UITestCase { static int width, height; static long durationPerTest = 600; - static long waitAbout10FramesAt30fps = 10*34; // 10 frames @ 30fps static GLCapabilities glCaps; @BeforeClass @@ -61,6 +60,37 @@ public class TestParenting01NEWT extends UITestCase { glCaps = new GLCapabilities(null); } + private static void waitForFrames(final String waitFor, final int prefixIdx, + final GLWindow glWindow1, final GLWindow glWindow2, + final long TO, final boolean doAssert) { + final long t0 = System.currentTimeMillis(); + int a, b; + long t1; + do { + try { Thread.sleep(16); } catch (final InterruptedException e) { } + if( null != glWindow1 ) { + a = glWindow1.getTotalFPSFrames(); + } else { + a = -1; + } + if( null != glWindow2 ) { + b = glWindow2.getTotalFPSFrames(); + } else { + b = -1; + } + t1 = System.currentTimeMillis(); + } while ( ( 0 == a || 0 == b ) && TO > ( t1 - t0 ) ); + System.err.println("Frames for "+waitFor+": A"+prefixIdx+": "+a+", B"+prefixIdx+": "+b); + if( doAssert ) { + if( null != glWindow1 ) { + Assert.assertTrue("No frames."+prefixIdx+" displayed on window1 during "+TO+"ms", 0 < a); + } + if( null != glWindow2 ) { + Assert.assertTrue("No frames."+prefixIdx+" displayed on window2 during "+TO+"ms", 0 < b); + } + } + } + @Test public void test01CreateVisibleDestroy() throws InterruptedException { Assert.assertEquals(0,Display.getActiveDisplayNumber()); @@ -111,11 +141,8 @@ public class TestParenting01NEWT extends UITestCase { // visible test Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); + System.err.println("XXX VISIBLE.1 -> TRUE"); glWindow1.setVisible(true); - System.err.println("Frames for setVisible(true): A1: "+glWindow1.getTotalFPSFrames()+", B1: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); - Assert.assertEquals(true, glWindow1.isVisible()); Assert.assertEquals(true, glWindow1.isNativeValid()); Assert.assertEquals(true, glWindow2.isVisible()); @@ -127,7 +154,9 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(2,screen.getReferenceCount()); Assert.assertEquals(true,screen.isNativeValid()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); + waitForFrames("window1.setVisible(true)", 1, glWindow1, glWindow2, 2000, true); + System.err.println("XXX VISIBLE.2 -> FALSE"); glWindow1.setVisible(false); Assert.assertEquals(false, glWindow1.isVisible()); Assert.assertEquals(true, glWindow1.isNativeValid()); @@ -138,15 +167,13 @@ public class TestParenting01NEWT extends UITestCase { glWindow2.resetFPSCounter(); Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); + System.err.println("XXX VISIBLE.3 -> TRUE"); glWindow1.setVisible(true); - System.err.println("Frames for setVisible(true): A2: "+glWindow1.getTotalFPSFrames()+", B2: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); - Assert.assertEquals(true, glWindow1.isVisible()); Assert.assertEquals(true, glWindow1.isNativeValid()); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); + waitForFrames("window1.setVisible(true)", 2, glWindow1, glWindow2, 2000, true); glWindow1.resetFPSCounter(); glWindow2.resetFPSCounter(); @@ -165,9 +192,7 @@ public class TestParenting01NEWT extends UITestCase { while(animator1.isAnimating() && animator1.getTotalFPSDuration()<durationPerTest) { Thread.sleep(100); } - System.err.println("Frames for setVisible(true): A3: "+glWindow1.getTotalFPSFrames()+", B3: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("animator.start()", 3, glWindow1, glWindow2, 2000, true); Assert.assertEquals(true, animator1.pause()); Assert.assertEquals(false, animator1.isAnimating()); @@ -188,10 +213,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true, animator2.isAnimating()); Assert.assertEquals(false, animator2.isPaused()); Assert.assertNotNull(animator2.getThread()); - Thread.sleep(waitAbout10FramesAt30fps); - System.err.println("Frames for setVisible(true): A4: "+glWindow1.getTotalFPSFrames()+", B4: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("animator.resume()", 4, glWindow1, glWindow2, 2000, true); animator1.stop(); Assert.assertEquals(false, animator1.isAnimating()); @@ -243,15 +265,13 @@ public class TestParenting01NEWT extends UITestCase { glWindow2.resetFPSCounter(); Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); + System.err.println("XXX VISIBLE.4 -> TRUE"); glWindow1.setVisible(true); Assert.assertEquals(true, glWindow1.isVisible()); Assert.assertEquals(true, glWindow1.isNativeValid()); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); - - System.err.println("Frames for setVisible(true): A3: "+glWindow1.getTotalFPSFrames()+", B3: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("window1.setVisible(true) recreate", 5, glWindow1, glWindow2, 2000, true); Assert.assertEquals(1,display.getReferenceCount()); Assert.assertEquals(true,display.isNativeValid()); @@ -348,12 +368,10 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true,screen1.isNativeValid()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); Assert.assertEquals(true, glWindow1.isVisible()); - System.err.println("Frames for setVisible(true) A1: "+glWindow1.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - + waitForFrames("window1.setVisible(true)", 1, glWindow1, null, 2000, true); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); - glWindow2.setVisible(true); + glWindow2.setVisible(true); Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); Assert.assertNotNull(display1.getEDTUtil()); @@ -362,8 +380,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true,screen1.isNativeValid()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); Assert.assertEquals(true, glWindow2.isVisible()); - System.err.println("Frames for setVisible(true) B1: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); + waitForFrames("window2.setVisible(true)", 2, glWindow1, glWindow2, 2000, true); final Animator animator1 = new Animator(glWindow1); animator1.setUpdateFPSFrames(1, null); @@ -405,9 +422,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); Assert.assertSame(glWindow1,glWindow2.getParent()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B2: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.child(parent, "+reparentRecreate+"), "+reparentAction, 10, glWindow1, glWindow2, 2000, true); Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); @@ -448,9 +463,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); Assert.assertNull(glWindow2.getParent()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B3: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.top(parent, "+reparentRecreate+"), "+reparentAction, 11, glWindow1, glWindow2, 2000, true); Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); @@ -579,10 +592,6 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertEquals(0, glWindow1.getTotalFPSFrames()); Assert.assertEquals(0, glWindow2.getTotalFPSFrames()); glWindow1.setVisible(true); - System.err.println("Frames for setVisible(): A1: "+glWindow1.getTotalFPSFrames()+", B1: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow1.getTotalFPSFrames()); - Assert.assertEquals(1,display1.getReferenceCount()); Assert.assertEquals(true,display1.isNativeValid()); Assert.assertNotNull(display1.getEDTUtil()); @@ -592,6 +601,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertSame(glWindow1,glWindow2.getParent()); Assert.assertSame(screen1,glWindow2.getScreen()); Assert.assertEquals(1,Display.getActiveDisplayNumber()); + waitForFrames("window1.setVisible(true)", 1, glWindow1, glWindow2, 2000, true); final Animator animator1 = new Animator(glWindow1); animator1.setUpdateFPSFrames(1, null); @@ -630,9 +640,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertTrue(Window.ReparentOperation.ACTION_INVALID != reparentAction); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B2: "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.top(parent, "+reparentRecreate+"), "+reparentAction, 10, glWindow1, glWindow2, 2000, true); Assert.assertNull(glWindow2.getParent()); Assert.assertSame(screen1,glWindow2.getScreen()); @@ -665,9 +673,7 @@ public class TestParenting01NEWT extends UITestCase { Assert.assertTrue(Window.ReparentOperation.ACTION_INVALID != reparentAction); Assert.assertEquals(true, glWindow2.isVisible()); Assert.assertEquals(true, glWindow2.isNativeValid()); - Thread.sleep(20*16); // Wait for a few frames since counter could be reset - 20 frames at 60Hz - System.err.println("Frames for reparentWindow(parent, "+reparentRecreate+"): "+reparentAction+", B3 "+glWindow2.getTotalFPSFrames()); - Assert.assertTrue(0 < glWindow2.getTotalFPSFrames()); + waitForFrames("reparentWindow.child(parent, "+reparentRecreate+"), "+reparentAction, 11, glWindow1, glWindow2, 2000, true); Assert.assertSame(glWindow1,glWindow2.getParent()); Assert.assertSame(screen1,glWindow2.getScreen()); |