From 9ddbfb35882aa4c361d161ab8aca91ed670a97c8 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 30 Nov 2012 15:02:07 +0100 Subject: Simplify NEWT EDTUtil invoke: To start EDT Runnable maybe null - start EDT even if on EDT thread. DEBUG: Name EDTUtil impl, e.g. Default, AWT and SWT --- src/newt/classes/jogamp/newt/DefaultEDTUtil.java | 42 +++++++++++----------- .../classes/jogamp/newt/driver/awt/AWTEDTUtil.java | 32 ++++++++--------- 2 files changed, 35 insertions(+), 39 deletions(-) (limited to 'src/newt/classes/jogamp') diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java index 98987ef96..b141f9d29 100644 --- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java +++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java @@ -81,10 +81,10 @@ public class DefaultEDTUtil implements EDTUtil { waitUntilStopped(); if(DEBUG) { if(edt.tasks.size()>0) { - System.err.println(Thread.currentThread()+": EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt); + System.err.println(Thread.currentThread()+": Default-EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt); // Thread.dumpStack(); } - System.err.println(Thread.currentThread()+": EDT reset - edt: "+edt); + System.err.println(Thread.currentThread()+": Default-EDT reset - edt: "+edt); } this.edt = new EventDispatchThread(threadGroup, name); this.edt.setDaemon(true); // don't stop JVM from shutdown .. @@ -93,13 +93,13 @@ public class DefaultEDTUtil implements EDTUtil { private final void startImpl() { if(edt.isAlive()) { - throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size()); + throw new RuntimeException("Default-EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size()); } start_iter++; edt.setName(name+start_iter); edt.shouldStop = false; if(DEBUG) { - System.err.println(Thread.currentThread()+": EDT START - edt: "+edt); + System.err.println(Thread.currentThread()+": Default-EDT START - edt: "+edt); // Thread.dumpStack(); } edt.start(); @@ -136,9 +136,6 @@ public class DefaultEDTUtil implements EDTUtil { } private void invokeImpl(boolean wait, Runnable task, boolean stop) { - if(task == null) { - throw new RuntimeException("Null Runnable"); - } Throwable throwable = null; RunnableTask rTask = null; Object rTaskLock = new Object(); @@ -147,7 +144,7 @@ public class DefaultEDTUtil implements EDTUtil { if( edt.shouldStop ) { // drop task .. if(DEBUG) { - System.err.println("Warning: EDT about (1) to stop, won't enqueue new task: "+edt); + System.err.println(Thread.currentThread()+": Warning: Default-EDT about (1) to stop, won't enqueue new task: "+edt); Thread.dumpStack(); } return; @@ -157,24 +154,25 @@ public class DefaultEDTUtil implements EDTUtil { if(stop) { edt.shouldStop = true; if(DEBUG) { - System.err.println(Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - tasks: "+edt.tasks.size()+" - "+edt); + System.err.println(Thread.currentThread()+": Default-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - tasks: "+edt.tasks.size()+" - "+edt); // Thread.dumpStack(); } + } else if( !edt.isRunning() ) { + // start if should not stop && not started yet + startImpl(); } - if( isCurrentThreadEDT() ) { + if( null == task ) { + wait = false; + } else if( isCurrentThreadEDT() ) { task.run(); wait = false; // running in same thread (EDT) -> no wait if(stop && edt.tasks.size()>0) { - System.err.println("Warning: EDT about (2) to stop, having remaining tasks: "+edt.tasks.size()+" - "+edt); + System.err.println(Thread.currentThread()+": Warning: Default-EDT about (2) to stop, having remaining tasks: "+edt.tasks.size()+" - "+edt); if(DEBUG) { Thread.dumpStack(); } } } else { - // start if should not stop && not started yet - if( !stop && !edt.isRunning() ) { - startImpl(); - } synchronized(edt.tasks) { wait = wait && edt.isRunning(); rTask = new RunnableTask(task, @@ -207,7 +205,7 @@ public class DefaultEDTUtil implements EDTUtil { } } if(DEBUG && stop) { - System.err.println(Thread.currentThread()+": EDT signal STOP X edt: "+edt); + System.err.println(Thread.currentThread()+": Default-EDT signal STOP X edt: "+edt); } } @@ -282,7 +280,7 @@ public class DefaultEDTUtil implements EDTUtil { @Override final public void run() { if(DEBUG) { - System.err.println(getName()+": EDT run() START "+ getName()); + System.err.println(getName()+": Default-EDT run() START "+ getName()); } validateNoRecursiveLocksHold(); RuntimeException error = null; @@ -324,12 +322,12 @@ public class DefaultEDTUtil implements EDTUtil { if(t instanceof RuntimeException) { error = (RuntimeException) t; } else { - error = new RuntimeException("Within EDT", t); + error = new RuntimeException("Within Default-EDT", t); } } finally { if(DEBUG) { RunnableTask rt = ( tasks.size() > 0 ) ? tasks.get(0) : null ; - System.err.println(getName()+": EDT run() END "+ getName()+", tasks: "+tasks.size()+", "+rt+", "+error); + System.err.println(getName()+": Default-EDT run() END "+ getName()+", tasks: "+tasks.size()+", "+rt+", "+error); } synchronized(edtLock) { if(null==error) { @@ -344,9 +342,9 @@ public class DefaultEDTUtil implements EDTUtil { } if(DEBUG) { if(null!=task && task.getAttachment()==null) { - System.err.println(getName()+" Warning: EDT exit: Last task Not Final: "+tasks.size()+", "+task+" - "+edt); + System.err.println(getName()+" Warning: Default-EDT exit: Last task Not Final: "+tasks.size()+", "+task+" - "+edt); } else if(tasks.size()>0) { - System.err.println(getName()+" Warning: EDT exit: Remaining tasks Post Final: "+tasks.size()); + System.err.println(getName()+" Warning: Default-EDT exit: Remaining tasks Post Final: "+tasks.size()); } Thread.dumpStack(); } @@ -358,7 +356,7 @@ public class DefaultEDTUtil implements EDTUtil { } } if(DEBUG) { - System.err.println(getName()+": EDT run() EXIT "+ getName()+", exception: "+error); + System.err.println(getName()+": Default-EDT run() EXIT "+ getName()+", exception: "+error); } if(null!=error) { throw error; diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java index 2175f2190..cb9bc90b8 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java @@ -72,7 +72,7 @@ public class AWTEDTUtil implements EDTUtil { synchronized(edtLock) { waitUntilStopped(); if(DEBUG) { - System.err.println(Thread.currentThread()+": EDT reset - edt: "+nedt); + System.err.println(Thread.currentThread()+": AWT-EDT reset - edt: "+nedt); } this.nedt = new NewtEventDispatchThread(threadGroup, name); this.nedt.setDaemon(true); // don't stop JVM from shutdown .. @@ -81,13 +81,13 @@ public class AWTEDTUtil implements EDTUtil { private final void startImpl() { if(nedt.isAlive()) { - throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); + throw new RuntimeException("AWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); } start_iter++; nedt.setName(name+start_iter); nedt.shouldStop = false; if(DEBUG) { - System.err.println(Thread.currentThread()+": EDT START - edt: "+nedt); + System.err.println(Thread.currentThread()+": AWT-EDT START - edt: "+nedt); // Thread.dumpStack(); } nedt.start(); @@ -124,9 +124,6 @@ public class AWTEDTUtil implements EDTUtil { } private void invokeImpl(boolean wait, Runnable task, boolean stop) { - if(task == null) { - throw new RuntimeException("Null Runnable"); - } Throwable throwable = null; RunnableTask rTask = null; Object rTaskLock = new Object(); @@ -135,7 +132,7 @@ public class AWTEDTUtil implements EDTUtil { if( nedt.shouldStop ) { // drop task .. if(DEBUG) { - System.err.println("Warning: EDT about (1) to stop, won't enqueue new task: "+nedt); + System.err.println(Thread.currentThread()+": Warning: AWT-EDT about (1) to stop, won't enqueue new task: "+nedt); Thread.dumpStack(); } return; @@ -145,18 +142,19 @@ public class AWTEDTUtil implements EDTUtil { if(stop) { nedt.shouldStop = true; if(DEBUG) { - System.err.println(Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); + System.err.println(Thread.currentThread()+": AWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); // Thread.dumpStack(); } + } else if( !nedt.isRunning() ) { + // start if should not stop && not started yet + startImpl(); } - if( isCurrentThreadEDT() ) { + if( null == task ) { + wait = false; + } else if( isCurrentThreadEDT() ) { task.run(); wait = false; // running in same thread (EDT) -> no wait } else { - // start if should not stop && not started yet - if( !stop && !nedt.isRunning() ) { - startImpl(); - } rTask = new RunnableTask(task, wait ? rTaskLock : null, true /* always catch and report Exceptions, don't disturb EDT */); @@ -239,7 +237,7 @@ public class AWTEDTUtil implements EDTUtil { @Override final public void run() { if(DEBUG) { - System.err.println(getName()+": EDT run() START "+ getName()); + System.err.println(getName()+": AWT-EDT run() START "+ getName()); } RuntimeException error = null; try { @@ -269,11 +267,11 @@ public class AWTEDTUtil implements EDTUtil { if(t instanceof RuntimeException) { error = (RuntimeException) t; } else { - error = new RuntimeException("Within EDT", t); + error = new RuntimeException("Within AWT-EDT", t); } } finally { if(DEBUG) { - System.err.println(getName()+": EDT run() END "+ getName()+", "+error); + System.err.println(getName()+": AWT-EDT run() END "+ getName()+", "+error); } synchronized(edtLock) { isRunning = !shouldStop; @@ -282,7 +280,7 @@ public class AWTEDTUtil implements EDTUtil { } } if(DEBUG) { - System.err.println(getName()+": EDT run() EXIT "+ getName()+", exception: "+error); + System.err.println(getName()+": AWT-EDT run() EXIT "+ getName()+", exception: "+error); } if(null!=error) { throw error; -- cgit v1.2.3 From 1f360ff73901b0a48f9ee310d8f2e5c4aad1e101 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 30 Nov 2012 15:50:22 +0100 Subject: NEWT WindowImpl: Don't issue native resize if invisible, simply use defineSize(..); Don't set persitent undecorated flag if child window at creation; Use local 'screen' directly. - Don't issue native resize if invisible, simply use defineSize(..) Invisible windows may not promote size change natively, hence simply setting the size via defineSize(..) is appropriate. Latter setVisible(true) will take size into account. - Don't set persitent undecorated flag if child window at creation Even if a window is a child at creation, it maybe reparented to top-level where the default behavior is to be expected. Undecorated top-level window shall require explicit setUndecorated(true). - Use local 'screen' directly. No need to make code more complicate .. --- src/newt/classes/jogamp/newt/WindowImpl.java | 31 ++++++++++++---------------- 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'src/newt/classes/jogamp') diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 4f8eb3d3a..5b26c3998 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -173,7 +173,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer window.parentWindowHandle = parentWindowHandle; window.screen = (ScreenImpl) screen; window.capsRequested = (CapabilitiesImmutable) caps.cloneMutable(); - window.setUndecorated(0!=parentWindowHandle); window.instantiationFinished(); return window; } catch (Throwable t) { @@ -804,11 +803,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } else if ( visible && !isNativeValid() && 0 < width && 0 < height ) { visibleAction = 2; // visible (create) defineSize(width, height); - } else if ( isNativeValid() ) { + } else if ( visible && isNativeValid() ) { visibleAction = 0; // this width/height will be set by windowChanged, called by the native implementation reconfigureWindowImpl(getX(), getY(), width, height, getReconfigureFlags(0, isVisible())); } else { + // invisible or invalid w/ 0 size visibleAction = 0; defineSize(width, height); } @@ -1045,8 +1045,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(null!=newParentWindowNEWT) { setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); } else { - Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, getScreen()); - if( getScreen() != newScreen ) { + final Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, screen); + if( screen != newScreen ) { // auto destroy on-the-fly created Screen/Display setScreen( (ScreenImpl) newScreen ); } @@ -1056,14 +1056,14 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } else { operation = ReparentOperation.ACTION_NATIVE_CREATION_PENDING; } - } else if ( forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { + } else if ( forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, screen) ) { // Destroy this window, may create a new compatible Screen/Display, // and mark it for creation. destroy(); if(null!=newParentWindowNEWT) { setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); } else { - setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, getScreen()) ); + setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, screen) ); } operation = ReparentOperation.ACTION_NATIVE_CREATION; } else { @@ -1078,7 +1078,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( null != parentWindow ) { // child -> top // put client to current parent+child position - Point p = getLocationOnScreen(null); + final Point p = getLocationOnScreen(null); x = p.getX(); y = p.getY(); } @@ -1134,7 +1134,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } if( ReparentOperation.ACTION_NATIVE_REPARENTING == operation ) { - DisplayImpl display = (DisplayImpl) screen.getDisplay(); + final DisplayImpl display = (DisplayImpl) screen.getDisplay(); display.dispatchMessagesNative(); // status up2date if(wasVisible) { @@ -1566,15 +1566,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public void runOnEDTIfAvail(boolean wait, final Runnable task) { - if(windowLock.isOwner(Thread.currentThread())) { + if( windowLock.isOwner( Thread.currentThread() ) ) { task.run(); } else { - Screen scrn = getScreen(); - if(null==scrn) { - throw new RuntimeException("Null screen of inner class: "+this); - } - DisplayImpl d = (DisplayImpl) scrn.getDisplay(); - d.runOnEDTIfAvail(wait, task); + ( (DisplayImpl) screen.getDisplay() ).runOnEDTIfAvail(wait, task); } } @@ -1899,7 +1894,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { if(isNativeValid()) { - ((DisplayImpl)getScreen().getDisplay()).enqueueEvent(wait, event); + ((DisplayImpl)screen.getDisplay()).enqueueEvent(wait, event); } } @@ -1914,7 +1909,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer repaintQueued=true; final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen(); if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.consumeEvent: "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO); + System.err.println("Window.consumeEvent: REPAINT "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO); // Thread.dumpStack(); } return discardTO; // discardTO:=true -> consumed @@ -1930,7 +1925,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( null != windowLock.getOwner() ) { final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen(); if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.consumeEvent: "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO); + System.err.println("Window.consumeEvent: RESIZED "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO); // Thread.dumpStack(); } return discardTO; // discardTO:=true -> consumed -- cgit v1.2.3 From b6f54d1714597ba2799160569b56139277db9e07 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 2 Dec 2012 03:55:08 +0100 Subject: NEWT WindowImpl fixes: surfaceLockCount-- if native lock fails; waitForVisible(.., fastFail:=false); waitForSize(..) @ setSize; reparent definePosition(..); - surfaceLockCount-- if native lock fails In case native lock fails, not only remove the windowLock but also decr. surfaceLockCount (proper roll back) - was a BUG! - waitForVisible(.., fastFail:=false) Don't fail fast if visibility wasn't reached. - waitForSize(..) @ setSize Wait for size change - otherwise an SWT child won't reach desired size. - reparent definePosition(..); Position might not get updated by WM events (SWT parent apparently) - Windows WindowDriver: Cleanup code a bit. --- src/newt/classes/jogamp/newt/WindowImpl.java | 50 ++++++++++++---------- .../jogamp/newt/driver/windows/WindowDriver.java | 14 +++--- 2 files changed, 36 insertions(+), 28 deletions(-) (limited to 'src/newt/classes/jogamp') diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 5b26c3998..a9294c1ff 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -572,6 +572,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } finally { if (LOCK_SURFACE_NOT_READY >= res) { + surfaceLockCount--; _wlock.unlock(); } } @@ -728,8 +729,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } else if(WindowImpl.this.visible != visible) { if(isNativeValid()) { setVisibleImpl(visible, getX(), getY(), getWidth(), getHeight()); - WindowImpl.this.waitForVisible(visible, true); + WindowImpl.this.waitForVisible(visible, false); madeVisible = visible; + } else { + WindowImpl.this.visible = true; } } @@ -807,6 +810,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer visibleAction = 0; // this width/height will be set by windowChanged, called by the native implementation reconfigureWindowImpl(getX(), getY(), width, height, getReconfigureFlags(0, isVisible())); + WindowImpl.this.waitForSize(width, height, false, TIMEOUT_NATIVEWINDOW); } else { // invisible or invalid w/ 0 size visibleAction = 0; @@ -1139,8 +1143,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(wasVisible) { setVisibleImpl(false, x, y, width, height); - WindowImpl.this.waitForVisible(false, true); - // some composite WM behave slacky .. give 'em chance to change state -> invisible, + WindowImpl.this.waitForVisible(false, false); + // FIXME: Some composite WM behave slacky .. give 'em chance to change state -> invisible, // even though we do exactly that (KDE+Composite) try { Thread.sleep(100); } catch (InterruptedException e) { } display.dispatchMessagesNative(); // status up2date @@ -1166,6 +1170,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer parentWindowLocked.unlockSurface(); } } + definePosition(x, y); // position might not get updated by WM events (SWT parent apparently) // set visible again if(ok) { @@ -1173,7 +1178,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(wasVisible) { setVisibleImpl(true, x, y, width, height); ok = WindowImpl.this.waitForVisible(true, false); - display.dispatchMessagesNative(); // status up2date if(ok) { ok = WindowImpl.this.waitForSize(width, height, false, TIMEOUT_NATIVEWINDOW); } @@ -1202,7 +1206,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.reparentWindow: END-1 ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+x+"/"+y+" "+width+"x"+height); + System.err.println("Window.reparentWindow: END-1 ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()); } } finally { _lock.unlock(); @@ -1223,7 +1227,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.reparentWindow: END-X ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+x+"/"+y+" "+width+"x"+height); + System.err.println("Window.reparentWindow: END-X ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()); } } } @@ -1557,7 +1561,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer for (int i = 0; i < keyListeners.size(); i++ ) { sb.append(keyListeners.get(i)+", "); } - sb.append("], windowLock "+windowLock+"]"); + sb.append("], windowLock "+windowLock+", surfaceLockCount "+surfaceLockCount+"]"); return sb.toString(); } @@ -2425,10 +2429,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } private boolean waitForVisible(boolean visible, boolean failFast, long timeOut) { - DisplayImpl display = (DisplayImpl) screen.getDisplay(); + final DisplayImpl display = (DisplayImpl) screen.getDisplay(); + display.dispatchMessagesNative(); // status up2date for(long sleep = timeOut; 0= sleep) { final String msg = "Size/Pos not reached as requested within "+timeOut+"ms : requested "+w+"x"+h+", is "+getWidth()+"x"+getHeight(); if(failFast) { throw new NativeWindowException(msg); @@ -2481,8 +2485,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer System.err.println(msg); Thread.dumpStack(); } + return false; + } else { + return true; } - return reached; } /** Triggered by implementation's WM events to update the position. */ diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java index 6aac8617c..2ec88852c 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java @@ -71,13 +71,15 @@ public class WindowDriver extends WindowImpl { if (0 != hdc) { throw new InternalError("surface not released"); } - hdc = GDI.GetDC(getWindowHandle()); - hmon = MonitorFromWindow0(getWindowHandle()); + final long hWnd = getWindowHandle(); + hdc = GDI.GetDC(hWnd); // return ( 0 == hdc ) ? LOCK_SURFACE_NOT_READY : ( hdc_old != hdc ) ? LOCK_SURFACE_CHANGED : LOCK_SUCCESS ; if( 0 == hdc ) { return LOCK_SURFACE_NOT_READY; - } + } + hmon = MonitorFromWindow0(hWnd); + if( hdc_old == hdc ) { return LOCK_SUCCESS; } @@ -217,14 +219,14 @@ public class WindowDriver extends WindowImpl { @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { - final Boolean[] res = new Boolean[] { Boolean.FALSE }; + final boolean[] res = new boolean[] { false }; this.runOnEDTIfAvail(true, new Runnable() { public void run() { - res[0] = Boolean.valueOf(setPointerVisible0(getWindowHandle(), pointerVisible)); + res[0] = setPointerVisible0(getWindowHandle(), pointerVisible); } }); - return res[0].booleanValue(); + return res[0]; } @Override -- cgit v1.2.3 From aa4b8c9abbf9529fdbb3c4982895c01f2698451f Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sun, 2 Dec 2012 04:09:41 +0100 Subject: NEWT EDTUtil: Simplify running state (default is running @ setEDTUtil()); Simplify DefaultEDTUtil impl. and fix concurrency leak w/ 'shouldStop' --- src/newt/classes/com/jogamp/newt/Display.java | 12 +-- .../classes/com/jogamp/newt/swt/SWTEDTUtil.java | 5 +- src/newt/classes/com/jogamp/newt/util/EDTUtil.java | 3 +- src/newt/classes/jogamp/newt/DefaultEDTUtil.java | 99 +++++++++++----------- src/newt/classes/jogamp/newt/DisplayImpl.java | 33 ++++---- .../classes/jogamp/newt/driver/awt/AWTEDTUtil.java | 5 +- .../junit/newt/TestDisplayLifecycle01NEWT.java | 4 +- 7 files changed, 81 insertions(+), 80 deletions(-) (limited to 'src/newt/classes/jogamp') diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 4c263a195..993aa33eb 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -158,19 +158,15 @@ public abstract class Display { *

*

* If a previous one exists and it differs from the new one, - * it's being stopped, wait-until-idle and reset to allow restart. + * it's being stopped, wait-until-idle and reset to allow a restart at a later time. *

*

* If newEDTUtil is not null and equals the previous one, - * null is returned and no change is being made. + * no change is being made. *

*

- * Note that newEDTUtil will not be started by this method. - * To do so you may issue {@link EDTUtil#invoke(boolean, Runnable) invoke} - * on the new EDTUtil: - *

-     *          newEDTUtil.invoke(true, null);
-     * 
+ * Note that newEDTUtil will be started by this method, + * if it is not running yet. *

*/ public abstract EDTUtil setEDTUtil(EDTUtil newEDTUtil); diff --git a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java index 2203d744a..1c20fe524 100644 --- a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java @@ -150,7 +150,10 @@ public class SWTEDTUtil implements EDTUtil { // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); // Thread.dumpStack(); if(stop) { - nedt.shouldStop = true; + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } if(DEBUG) { System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); // Thread.dumpStack(); diff --git a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java index 293e13592..0183da592 100644 --- a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java @@ -113,7 +113,8 @@ public interface EDTUtil { /** * Append the final task to the EDT task queue, - * signals EDT to stop and wait until stopped.
+ * signals EDT to stop and wait until stopped.
+ * task maybe null
* Due to the nature of this method: *
    *
  • All previous queued tasks will be finished.
  • diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java index b141f9d29..d8d04e79f 100644 --- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java +++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java @@ -135,6 +135,11 @@ public class DefaultEDTUtil implements EDTUtil { invokeImpl(wait, task, false); } + private static Runnable nullTask = new Runnable() { + @Override + public void run() { } + }; + private void invokeImpl(boolean wait, Runnable task, boolean stop) { Throwable throwable = null; RunnableTask rTask = null; @@ -151,39 +156,50 @@ public class DefaultEDTUtil implements EDTUtil { } // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); // Thread.dumpStack(); - if(stop) { - edt.shouldStop = true; - if(DEBUG) { - System.err.println(Thread.currentThread()+": Default-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - tasks: "+edt.tasks.size()+" - "+edt); - // Thread.dumpStack(); + if( isCurrentThreadEDT() ) { + if(null != task) { + task.run(); } - } else if( !edt.isRunning() ) { - // start if should not stop && not started yet - startImpl(); - } - if( null == task ) { - wait = false; - } else if( isCurrentThreadEDT() ) { - task.run(); wait = false; // running in same thread (EDT) -> no wait - if(stop && edt.tasks.size()>0) { - System.err.println(Thread.currentThread()+": Warning: Default-EDT about (2) to stop, having remaining tasks: "+edt.tasks.size()+" - "+edt); - if(DEBUG) { - Thread.dumpStack(); + if(stop) { + edt.shouldStop = true; + if( edt.tasks.size()>0 ) { + System.err.println(Thread.currentThread()+": Warning: Default-EDT about (2) to stop, task executed. Remaining tasks: "+edt.tasks.size()+" - "+edt); + if(DEBUG) { + Thread.dumpStack(); + } } } } else { - synchronized(edt.tasks) { - wait = wait && edt.isRunning(); - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - true /* always catch and report Exceptions, don't disturb EDT */); - if(stop) { - rTask.setAttachment(new Boolean(true)); // mark final task + if( !edt.isRunning() ) { + if( !stop ) { + startImpl(); + } else { + // drop task and don't wait + task = null; + System.err.println(Thread.currentThread()+": Warning: Default-EDT is about (3) to stop and stopped already, dropping task. Remaining tasks: "+edt.tasks.size()+" - "+edt); + if(true || DEBUG) { + Thread.dumpStack(); + } + } + } else if(stop && null == task) { + task = nullTask; + } + + if(null != task) { + synchronized(edt.tasks) { + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */); + if(stop) { + rTask.setAttachment(new Boolean(true)); // mark final task, will imply shouldStop:=true + } + // append task .. + edt.tasks.add(rTask); + edt.tasks.notifyAll(); } - // append task .. - edt.tasks.add(rTask); - edt.tasks.notifyAll(); + } else { + wait = false; } } } @@ -305,6 +321,9 @@ public class DefaultEDTUtil implements EDTUtil { if(tasks.size()>0) { task = tasks.remove(0); tasks.notifyAll(); + if( null != task.getAttachment() ) { + shouldStop = true; + } } } if(null!=task) { @@ -330,30 +349,8 @@ public class DefaultEDTUtil implements EDTUtil { System.err.println(getName()+": Default-EDT run() END "+ getName()+", tasks: "+tasks.size()+", "+rt+", "+error); } synchronized(edtLock) { - if(null==error) { - synchronized(tasks) { - // drain remaining tasks (stop not on EDT), - // while having tasks and no previous-task, or previous-task is non final - RunnableTask task = null; - while ( ( null == task || task.getAttachment() == null ) && tasks.size() > 0 ) { - task = tasks.remove(0); - task.run(); - tasks.notifyAll(); - } - if(DEBUG) { - if(null!=task && task.getAttachment()==null) { - System.err.println(getName()+" Warning: Default-EDT exit: Last task Not Final: "+tasks.size()+", "+task+" - "+edt); - } else if(tasks.size()>0) { - System.err.println(getName()+" Warning: Default-EDT exit: Remaining tasks Post Final: "+tasks.size()); - } - Thread.dumpStack(); - } - } - } - isRunning = !shouldStop; - if(!isRunning) { - edtLock.notifyAll(); - } + isRunning = false; + edtLock.notifyAll(); } if(DEBUG) { System.err.println(getName()+": Default-EDT run() EXIT "+ getName()+", exception: "+error); diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index 317535805..20b915cae 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -84,9 +84,8 @@ public abstract class DisplayImpl extends Display { display.hashCode = display.fqname.hashCode(); displayList.add(display); } - if(null == display.edtUtil) { - display.setEDTUtil(null); // device's default if EDT is used, or null - } + display.setEDTUtil(display.edtUtil); // device's default if EDT is used, or null + if(DEBUG) { System.err.println("Display.create() NEW: "+display+" "+getThreadName()); } @@ -166,20 +165,24 @@ public abstract class DisplayImpl extends Display { @Override public EDTUtil setEDTUtil(EDTUtil newEDTUtil) { + final EDTUtil oldEDTUtil = edtUtil; if(null == newEDTUtil) { - newEDTUtil = createEDTUtil(); - } else if( newEDTUtil == edtUtil ) { if(DEBUG) { - System.err.println("Display.setEDTUtil: "+newEDTUtil+" - keep!"); + System.err.println("Display.setEDTUtil(default): "+oldEDTUtil+" -> "+newEDTUtil); + } + edtUtil = createEDTUtil(); + } else if( newEDTUtil != edtUtil ) { + if(DEBUG) { + System.err.println("Display.setEDTUtil(custom): "+oldEDTUtil+" -> "+newEDTUtil); } - return null; // no change + removeEDT( null ); + edtUtil = newEDTUtil; + } else if( DEBUG ) { + System.err.println("Display.setEDTUtil: "+newEDTUtil+" - keep!"); } - final EDTUtil oldEDTUtil = edtUtil; - if(DEBUG) { - System.err.println("Display.setEDTUtil: "+oldEDTUtil+" -> "+newEDTUtil); + if( !edtUtil.isRunning() ) { // start EDT if not running yet + edtUtil.invoke(true, null); } - removeEDT( new Runnable() { public void run() {} } ); - edtUtil = newEDTUtil; return oldEDTUtil; } @@ -209,11 +212,7 @@ public abstract class DisplayImpl extends Display { public boolean validateEDT() { if(0==refCount && null==aDevice && null != edtUtil && edtUtil.isRunning()) { - removeEDT( new Runnable() { - public void run() { - // nop - } - } ); + removeEDT( null ); return true; } return false; diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java index cb9bc90b8..27d0f3506 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java @@ -140,7 +140,10 @@ public class AWTEDTUtil implements EDTUtil { // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); // Thread.dumpStack(); if(stop) { - nedt.shouldStop = true; + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } if(DEBUG) { System.err.println(Thread.currentThread()+": AWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); // Thread.dumpStack(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java index c9450c2d6..e4867e3fe 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java @@ -89,7 +89,7 @@ public class TestDisplayLifecycle01NEWT extends UITestCase { Assert.assertEquals(0,display.getReferenceCount()); Assert.assertEquals(false,display.isNativeValid()); Assert.assertNotNull(display.getEDTUtil()); - Assert.assertEquals(false,display.getEDTUtil().isRunning()); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); Assert.assertEquals(0,screen.getReferenceCount()); Assert.assertEquals(false,screen.isNativeValid()); @@ -201,6 +201,8 @@ public class TestDisplayLifecycle01NEWT extends UITestCase { Assert.assertEquals(false,display.isNativeValid()); Assert.assertNotNull(display.getEDTUtil()); Assert.assertEquals(false,display.getEDTUtil().isRunning()); + display.getEDTUtil().invoke(true, null); + Assert.assertEquals(true,display.getEDTUtil().isRunning()); Assert.assertEquals(0,screen.getReferenceCount()); Assert.assertEquals(false,screen.isNativeValid()); -- cgit v1.2.3 From 7cb6cf2a9708d3f4e06f2215eb0d06b00fa6cd15 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 4 Dec 2012 07:10:59 +0100 Subject: SWT GLCanvas: Fix sporadic drop of redraw on X11 _and_ allow using custom GLCapabilities on X11 (feature complete) To allow custom GLCapabilities, we had to use native parenting on X11 w/ a new child window. The desired visualID chosen by the users GLCapabilities is passed to the new child window. The redraw drops must be caused by the original GDK or the new child GDK window. Now we use a plain X11 child window similar to NEWT's X11 window and NewtCanvasSWT, which doesn't expose this bug. (Note: SWTAccessor/GLCanvas still contains the uncommented GDK code path for further inspection, if desired) Also added SWTNewtEventFactory to test event handling on the SWT GLCanvas w/ GearsES2. TestSWTJOGLGLCanvas01GLn tests custom GLCapabilities now. SWTEDTUtil has been moved to private: com.jogamp.newt.swt -> jogamp.newt.swt. --- make/build-common.xml | 1 + make/build-newt.xml | 2 +- make/config/nativewindow/x11-CustomJavaCode.java | 5 +- make/scripts/tests-x32.sh | 2 + make/scripts/tests-x64.bat | 4 +- make/scripts/tests.sh | 6 +- .../classes/com/jogamp/opengl/swt/GLCanvas.java | 350 ++++++++++++++------- .../com/jogamp/nativewindow/swt/SWTAccessor.java | 345 +++++++++++++------- .../x11/X11DummyUpstreamSurfaceHook.java | 4 +- src/nativewindow/native/x11/Xmisc.c | 123 +++++++- .../classes/com/jogamp/newt/swt/NewtCanvasSWT.java | 82 +++-- .../classes/com/jogamp/newt/swt/SWTEDTUtil.java | 313 ------------------ src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java | 313 ++++++++++++++++++ .../jogamp/newt/swt/event/SWTNewtEventFactory.java | 249 +++++++++++++++ .../opengl/test/junit/jogl/demos/es2/GearsES2.java | 8 +- .../swt/TestNewtCanvasSWTBug628ResizeDeadlock.java | 5 +- .../junit/jogl/swt/TestSWTBug643AsyncExec.java | 26 +- .../junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java | 16 +- 18 files changed, 1236 insertions(+), 618 deletions(-) delete mode 100644 src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java create mode 100644 src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java create mode 100644 src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java (limited to 'src/newt/classes/jogamp') diff --git a/make/build-common.xml b/make/build-common.xml index a718ae09a..414b0eba2 100644 --- a/make/build-common.xml +++ b/make/build-common.xml @@ -428,6 +428,7 @@ + diff --git a/make/build-newt.xml b/make/build-newt.xml index 7b9a51863..c3b51141f 100644 --- a/make/build-newt.xml +++ b/make/build-newt.xml @@ -112,7 +112,7 @@ value="com/jogamp/newt/awt/** com/jogamp/newt/event/awt/** jogamp/newt/awt/** ${java.part.driver.awt}"/> + value="com/jogamp/newt/swt/** jogamp/newt/swt/**"/> diff --git a/make/config/nativewindow/x11-CustomJavaCode.java b/make/config/nativewindow/x11-CustomJavaCode.java index 8e5da3b2d..4240c5e2f 100644 --- a/make/config/nativewindow/x11-CustomJavaCode.java +++ b/make/config/nativewindow/x11-CustomJavaCode.java @@ -28,8 +28,9 @@ public static native int DefaultVisualID(long display, int screen); - public static native long CreateDummyWindow(long display, int screen_index, int visualID, int width, int height); - public static native void DestroyDummyWindow(long display, long window); + public static native long CreateWindow(long parent, long display, int screen_index, int visualID, int width, int height, boolean input, boolean visible); + public static native void DestroyWindow(long display, long window); + public static native void SetWindowPosSize(long display, long window, int x, int y, int width, int height); public static Point GetRelativeLocation(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y) { return (Point) GetRelativeLocation0(display, screen_index, src_win, dest_win, src_x, src_y); diff --git a/make/scripts/tests-x32.sh b/make/scripts/tests-x32.sh index a3aed84c3..858ed5fd8 100755 --- a/make/scripts/tests-x32.sh +++ b/make/scripts/tests-x32.sh @@ -6,6 +6,8 @@ if [ -e $SDIR/../../../gluegen/make/scripts/setenv-build-jogl-x86.sh ] ; then . $SDIR/../../../gluegen/make/scripts/setenv-build-jogl-x86.sh fi +export SWT_CLASSPATH=`pwd`/lib/swt/gtk-linux-x86/swt-debug.jar + . $SDIR/tests.sh `which java` -d32 ../build-x86 $* diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat index 7a2946d31..db7e27264 100755 --- a/make/scripts/tests-x64.bat +++ b/make/scripts/tests-x64.bat @@ -54,10 +54,10 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestP REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn %* -REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %* +scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTBug628ResizeDeadlock %* -scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec %* +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec %* REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestWindows01NEWT REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 0669efb37..628ab706b 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -113,7 +113,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLProfile" #D_ARGS="-Djogl.debug.GLProfile" #D_ARGS="-Dnativewindow.debug.NativeWindow" - #D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT" + D_ARGS="-Djogl.debug.GLCanvas -Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT -Djogl.debug.Animator" #D_ARGS="-Dnewt.debug.EDT -Dnewt.debug.Window -Djogl.debug.GLContext" #D_ARGS="-Dnativewindow.debug.X11Util.XErrorStackDump -Dnativewindow.debug.X11Util.TraceDisplayLifecycle -Dnativewindow.debug.X11Util" #D_ARGS="-Dnativewindow.debug.X11Util -Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnewt.debug=all" @@ -370,10 +370,10 @@ function testawtswt() { # #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTEclipseGLCanvas01GLn $* #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn $* -#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $* +testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $* #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn $* #testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTBug628ResizeDeadlock $* -testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec $* +#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec $* # # newt.awt (testawt) diff --git a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java index a080a7045..0320c63ae 100644 --- a/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/swt/GLCanvas.java @@ -29,10 +29,16 @@ package com.jogamp.opengl.swt; import java.util.List; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.nativewindow.VisualIDHolder; +import javax.media.nativewindow.VisualIDHolder.VIDType; import javax.media.opengl.GL; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; @@ -48,23 +54,20 @@ import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; import javax.media.opengl.Threading; +import jogamp.nativewindow.x11.X11Util; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableHelper; import jogamp.opengl.GLDrawableImpl; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import com.jogamp.common.GlueGenVersion; @@ -73,13 +76,14 @@ import com.jogamp.common.util.VersionUtil; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.nativewindow.swt.SWTAccessor; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.opengl.JoglVersion; /** * Native SWT Canvas implementing GLAutoDrawable - * - *

    Note: To employ custom GLCapabilities, NewtCanvasSWT shall be used instead.

    - * + *

    + * Implementation allows use of custom {@link GLCapabilities}. + *

    */ public class GLCanvas extends Canvas implements GLAutoDrawable { private static final boolean DEBUG = Debug.debug("GLCanvas"); @@ -103,11 +107,15 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { private final GLCapabilitiesImmutable capsRequested; private final GLCapabilitiesChooser capsChooser; + private volatile Rectangle clientArea; private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access - private GLContextImpl context; + private volatile GLContextImpl context; /* Native window surface */ - private AbstractGraphicsDevice device; + private final boolean useX11GTK; + private volatile long gdkWindow; // either GDK child window .. + private volatile long x11Window; // .. or X11 child window (for GL rendering) + private final AbstractGraphicsScreen screen; /* Construction parameters stored for GLAutoDrawable accessor methods */ private int additionalCtxCreationFlags = 0; @@ -135,7 +143,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void run() { if (sendReshape) { - helper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); + helper.reshape(GLCanvas.this, 0, 0, clientArea.width, clientArea.height); sendReshape = false; } helper.display(GLCanvas.this); @@ -143,7 +151,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { }; /* Action to make specified context current prior to running displayAction */ - private final Runnable makeCurrentAndDisplayOnEDTAction = new Runnable() { + private final Runnable makeCurrentAndDisplayOnGLAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; @@ -159,13 +167,14 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { }; /* Swaps buffers, assuming the GLContext is current */ - private final Runnable swapBuffersOnEDTAction = new Runnable() { + private final Runnable swapBuffersOnGLAction = new Runnable() { @Override public void run() { final RecursiveLock _lock = lock; _lock.lock(); try { - if(null != drawable && !GLCanvas.this.isDisposed() ) { + final boolean drawableOK = null != drawable && drawable.isRealized(); + if( drawableOK && !GLCanvas.this.isDisposed() ) { drawable.swapBuffers(); } } finally { @@ -212,10 +221,14 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { drawable.setRealized(false); drawable = null; } - if (null != device) { - device.close(); - device = null; + if( 0 != x11Window) { + SWTAccessor.destroyX11Window(screen.getDevice(), x11Window); + x11Window = 0; + } else if( 0 != gdkWindow) { + SWTAccessor.destroyGDKWindow(gdkWindow); + gdkWindow = 0; } + screen.getDevice().close(); if (animatorPaused) { animator.resume(); @@ -249,11 +262,6 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } }; - /** - * Storage for the client area rectangle so that it may be accessed from outside of the SWT thread. - */ - private volatile Rectangle clientArea; - /** * Creates an instance using {@link #GLCanvas(Composite, int, GLCapabilitiesImmutable, GLCapabilitiesChooser, GLContext)} * on the SWT thread. @@ -293,72 +301,80 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { * @param style * Optional SWT style bit-field. The {@link SWT#NO_BACKGROUND} bit is set before passing this up to the * Canvas constructor, so OpenGL handles the background. - * @param caps + * @param capsReqUser * Optional GLCapabilities. If not provided, the default capabilities for the default GLProfile for the * graphics device determined by the parent Composite are used. Note that the GLCapabilities that are * actually used may differ based on the capabilities of the graphics device. - * @param chooser + * @param capsChooser * Optional GLCapabilitiesChooser to customize the selection of the used GLCapabilities based on the * requested GLCapabilities, and the available capabilities of the graphics device. * @param shareWith * Optional GLContext to share state (textures, vbos, shaders, etc.) with. */ - public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable caps, - final GLCapabilitiesChooser chooser, final GLContext shareWith) { + public GLCanvas(final Composite parent, final int style, GLCapabilitiesImmutable capsReqUser, + final GLCapabilitiesChooser capsChooser, final GLContext shareWith) { /* NO_BACKGROUND required to avoid clearing bg in native SWT widget (we do this in the GL display) */ super(parent, style | SWT.NO_BACKGROUND); GLProfile.initSingleton(); // ensure JOGL is completly initialized SWTAccessor.setRealized(this, true); - + clientArea = GLCanvas.this.getClientArea(); /* Get the nativewindow-Graphics Device associated with this control (which is determined by the parent Composite). * Note: SWT is owner of the native handle, hence closing operation will be a NOP. */ - device = SWTAccessor.getDevice(this); + final AbstractGraphicsDevice swtDevice = SWTAccessor.getDevice(this); + + useX11GTK = SWTAccessor.useX11GTK(); + if(useX11GTK) { + // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering + final long x11DeviceHandle = X11Util.openDisplay(swtDevice.getConnection()); + if( 0 == x11DeviceHandle ) { + throw new RuntimeException("Error creating display(EDT): "+swtDevice.getConnection()); + } + final AbstractGraphicsDevice x11Device = new X11GraphicsDevice(x11DeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); + screen = SWTAccessor.getScreen(x11Device, -1 /* default */); + } else { + screen = SWTAccessor.getScreen(swtDevice, -1 /* default */); + } /* Select default GLCapabilities if none was provided, otherwise clone provided caps to ensure safety */ - if(null == caps) { - caps = new GLCapabilities(GLProfile.getDefault(device)); + if(null == capsReqUser) { + capsReqUser = new GLCapabilities(GLProfile.getDefault(screen.getDevice())); } - this.capsRequested = caps; - this.capsChooser = chooser; + + this.capsRequested = capsReqUser; + this.capsChooser = capsChooser; this.shareWith = shareWith; // post create .. when ready + gdkWindow = 0; + x11Window = 0; drawable = null; context = null; - /* Register SWT listeners (e.g. PaintListener) to render/resize GL surface. */ - /* TODO: verify that these do not need to be manually de-registered when destroying the SWT component */ - addPaintListener(new PaintListener() { - @Override - public void paintControl(final PaintEvent arg0) { - if ( !helper.isAnimatorAnimatingOnOtherThread() ) { - display(); // checks: null != drawable - } - } - }); - - addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(final ControlEvent arg0) { - updateSizeCheck(); - } - }); - - addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - GLCanvas.this.dispose(); - } - }); + final Listener listener = new Listener () { + @Override + public void handleEvent (Event event) { + switch (event.type) { + case SWT.Paint: + displayIfNoAnimatorNoCheck(); + break; + case SWT.Resize: + updateSizeCheck(); + break; + case SWT.Dispose: + GLCanvas.this.dispose(); + break; + } + } + }; + addListener (SWT.Resize, listener); + addListener (SWT.Paint, listener); + addListener (SWT.Dispose, listener); } + private final UpstreamSurfaceHook swtCanvasUpStreamHook = new UpstreamSurfaceHook() { @Override public final void create(ProxySurface s) { /* nop */ } @@ -390,11 +406,13 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { ) { clientArea = nClientArea; // write back new value - GLDrawableImpl _drawable = drawable; - if( null != _drawable ) { - if(DEBUG) { - System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle())); - } + final GLDrawableImpl _drawable = drawable; + final boolean drawableOK = null != _drawable && _drawable.isRealized(); + if(DEBUG) { + final long dh = drawableOK ? _drawable.getHandle() : 0; + System.err.println("GLCanvas.sizeChanged: ("+Thread.currentThread().getName()+"): "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - drawableHandle 0x"+Long.toHexString(dh)); + } + if( drawableOK ) { if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { final RecursiveLock _lock = lock; _lock.lock(); @@ -407,66 +425,154 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } finally { _lock.unlock(); } - } - sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock - } + } + } + if(0 != x11Window) { + SWTAccessor.resizeX11Window(screen.getDevice(), clientArea, x11Window); + } else if(0 != gdkWindow) { + SWTAccessor.resizeGDKWindow(clientArea, gdkWindow); + } + sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock } } - @Override - public void display() { - if( null != drawable || validateDrawableAndContext() ) { - runInGLThread(makeCurrentAndDisplayOnEDTAction); - } + private boolean isValidAndVisibleOnEDTActionResult; + private final Runnable isValidAndVisibleOnEDTAction = new Runnable() { + @Override + public void run() { + isValidAndVisibleOnEDTActionResult = !GLCanvas.this.isDisposed() && GLCanvas.this.isVisible(); + } }; + + private final boolean isValidAndVisibleOnEDT() { + synchronized(isValidAndVisibleOnEDTAction) { + runOnEDTIfAvail(true, isValidAndVisibleOnEDTAction); + return isValidAndVisibleOnEDTActionResult; + } } - - /** assumes drawable == null ! */ - protected final boolean validateDrawableAndContext() { - if( isDisposed() || !isVisible() ) { + /** assumes drawable == null || !drawable.isRealized() ! Checks of !isDispose() and isVisible() */ + protected final boolean validateDrawableAndContextWithCheck() { + if( !isValidAndVisibleOnEDT() ) { return false; } + return validateDrawableAndContextPostCheck(); + } + + /** assumes drawable == null || !drawable.isRealized() ! No check of !isDispose() and isVisible() */ + protected final boolean validateDrawableAndContextPostCheck() { final Rectangle nClientArea = clientArea; if(0 >= nClientArea.width || 0 >= nClientArea.height) { return false; } + final boolean res; final RecursiveLock _lock = lock; _lock.lock(); try { - final GLDrawableFactory glFactory = GLDrawableFactory.getFactory(capsRequested.getGLProfile()); - - /* Native handle for the control, used to associate with GLContext */ - final long nativeWindowHandle = SWTAccessor.getWindowHandle(this); - - /* Create a NativeWindow proxy for the SWT canvas */ - ProxySurface proxySurface = null; - try { - proxySurface = glFactory.createProxySurface(device, 0 /* screenIdx */, nativeWindowHandle, - capsRequested, capsChooser, swtCanvasUpStreamHook); - } catch (GLException gle) { - // not ready yet .. - if(DEBUG) { System.err.println(gle.getMessage()); } + if(null == drawable) { + createDrawableAndContext(); } - - if(null != proxySurface) { - /* Associate a GL surface with the proxy */ - drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); + if(null != drawable) { drawable.setRealized(true); - - context = (GLContextImpl) drawable.createContext(shareWith); + res = drawable.isRealized(); + } else { + res = false; } } finally { _lock.unlock(); + } + + if(res) { + sendReshape = true; + if(DEBUG) { + System.err.println("SWT GLCanvas realized! "+this+", "+drawable); + // Thread.dumpStack(); + } } - final boolean res = null != drawable; - if(DEBUG && res) { - System.err.println("SWT GLCanvas realized! "+this+", "+drawable); - Thread.dumpStack(); - } - return res; + return res; + } + + private final void createDrawableAndContext() { + final AbstractGraphicsDevice device = screen.getDevice(); + device.open(); + + final long nativeWindowHandle; + if( useX11GTK ) { + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(device, capsRequested); + final AbstractGraphicsConfiguration cfg = factory.chooseGraphicsConfiguration( + capsRequested, capsRequested, capsChooser, screen, VisualIDHolder.VID_UNDEFINED); + if(DEBUG) { + System.err.println("SWT.GLCanvas.X11 factory: "+factory+", chosen config: "+cfg); + } + if (null == cfg) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + final int visualID = cfg.getVisualID(VIDType.NATIVE); + if( VisualIDHolder.VID_UNDEFINED != visualID ) { + // gdkWindow = SWTAccessor.createCompatibleGDKChildWindow(this, visualID, clientArea.width, clientArea.height); + // nativeWindowHandle = SWTAccessor.gdk_window_get_xwindow(gdkWindow); + x11Window = SWTAccessor.createCompatibleX11ChildWindow(screen, this, visualID, clientArea.width, clientArea.height); + nativeWindowHandle = x11Window; + } else { + throw new GLException("Could not choose valid visualID: 0x"+Integer.toHexString(visualID)+", "+this); + } + } else { + nativeWindowHandle = SWTAccessor.getWindowHandle(this); + } + final GLDrawableFactory glFactory = GLDrawableFactory.getFactory(capsRequested.getGLProfile()); + + // Create a NativeWindow proxy for the SWT canvas + ProxySurface proxySurface = glFactory.createProxySurface(device, screen.getIndex(), nativeWindowHandle, + capsRequested, capsChooser, swtCanvasUpStreamHook); + // Associate a GL surface with the proxy + drawable = (GLDrawableImpl) glFactory.createGLDrawable(proxySurface); + context = (GLContextImpl) drawable.createContext(shareWith); + context.setContextCreationFlags(additionalCtxCreationFlags); + } + + @Override + public void update() { + // don't paint background etc .. nop avoids flickering + // super.update(); + } + + /** + @Override + public boolean forceFocus() { + final boolean r = super.forceFocus(); + if(r && 0 != gdkWindow) { + SWTGTKUtil.focusGDKWindow(gdkWindow); + } + return r; + } */ + + @Override + public void dispose() { + runInGLThread(disposeOnEDTGLAction); + super.dispose(); + } + + private final void displayIfNoAnimatorNoCheck() { + if ( !helper.isAnimatorAnimatingOnOtherThread() ) { + final boolean drawableOK = null != drawable && drawable.isRealized(); + if( drawableOK || validateDrawableAndContextPostCheck() ) { + runInGLThread(makeCurrentAndDisplayOnGLAction); + } + } } + // + // GL[Auto]Drawable + // + + @Override + public void display() { + final boolean drawableOK = null != drawable && drawable.isRealized(); + if( drawableOK || validateDrawableAndContextWithCheck() ) { + runInGLThread(makeCurrentAndDisplayOnGLAction); + } + } + @Override public final Object getUpstreamWidget() { return this; @@ -692,18 +798,7 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { @Override public void swapBuffers() throws GLException { - runInGLThread(swapBuffersOnEDTAction); - } - - @Override - public void update() { - // don't paint background etc .. nop avoids flickering - } - - @Override - public void dispose() { - runInGLThread(disposeOnEDTGLAction); - super.dispose(); + runInGLThread(swapBuffersOnGLAction); } /** @@ -746,7 +841,32 @@ public class GLCanvas extends Canvas implements GLAutoDrawable { } */ action.run(); } + + private void runOnEDTIfAvail(boolean wait, final Runnable action) { + final Display d = isDisposed() ? null : getDisplay(); + if( null == d || d.isDisposed() || d.getThread() == Thread.currentThread() ) { + action.run(); + } else if(wait) { + d.syncExec(action); + } else { + d.asyncExec(action); + } + } + + @Override + public String toString() { + final GLDrawable _drawable = drawable; + final int dw = (null!=_drawable) ? _drawable.getWidth() : -1; + final int dh = (null!=_drawable) ? _drawable.getHeight() : -1; + return "SWT-GLCanvas[Realized "+isRealized()+ + ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+ + ",\n\tFactory "+getFactory()+ + ",\n\thandle 0x"+Long.toHexString(getHandle())+ + ",\n\tDrawable size "+dw+"x"+dh+ + ",\n\tSWT size "+getWidth()+"x"+getHeight()+"]"; + } + public static void main(final String[] args) { System.err.println(VersionUtil.getPlatformInfo()); System.err.println(GlueGenVersion.getInstance()); diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java index e208cfb28..eba26c7d3 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/swt/SWTAccessor.java @@ -34,6 +34,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import org.eclipse.swt.graphics.GCData; +import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; import javax.media.nativewindow.AbstractGraphicsScreen; @@ -59,12 +60,22 @@ public class SWTAccessor { private static final Field swt_control_handle; private static final boolean swt_uses_long_handles; + private static Object swt_osx_init = new Object(); + private static Field swt_osx_control_view = null; + private static Field swt_osx_view_id = null; + + private static final String nwt; + private static final boolean isOSX; + private static final boolean isWindows; + private static final boolean isX11; + private static final boolean isX11GTK; + // X11/GTK, Windows/GDI, .. private static final String str_handle = "handle"; // OSX/Cocoa - private static final String str_view = "view"; // OSX - private static final String str_id = "id"; // OSX + private static final String str_osx_view = "view"; // OSX + private static final String str_osx_id = "id"; // OSX // static final String str_NSView = "org.eclipse.swt.internal.cocoa.NSView"; private static final Method swt_control_internal_new_GC; @@ -73,9 +84,10 @@ public class SWTAccessor { private static final String str_internal_dispose_GC = "internal_dispose_GC"; private static final String str_OS_gtk_class = "org.eclipse.swt.internal.gtk.OS"; - private static final Class OS_gtk_class; + public static final Class OS_gtk_class; private static final String str_OS_gtk_version = "GTK_VERSION"; - private static final VersionNumber OS_gtk_version; + public static final VersionNumber OS_gtk_version; + private static final Method OS_gtk_widget_realize; private static final Method OS_gtk_widget_unrealize; // optional (removed in SWT 4.3) private static final Method OS_GTK_WIDGET_WINDOW; @@ -85,6 +97,8 @@ public class SWTAccessor { private static final Method OS_gdk_window_get_display; private static final Method OS_gdk_x11_drawable_get_xid; private static final Method OS_gdk_x11_window_get_xid; + private static final Method OS_gdk_window_set_back_pixmap; + private static final String str_gtk_widget_realize = "gtk_widget_realize"; private static final String str_gtk_widget_unrealize = "gtk_widget_unrealize"; private static final String str_GTK_WIDGET_WINDOW = "GTK_WIDGET_WINDOW"; @@ -94,6 +108,7 @@ public class SWTAccessor { private static final String str_gdk_window_get_display = "gdk_window_get_display"; private static final String str_gdk_x11_drawable_get_xid = "gdk_x11_drawable_get_xid"; private static final String str_gdk_x11_window_get_xid = "gdk_x11_window_get_xid"; + private static final String str_gdk_window_set_back_pixmap = "gdk_window_set_back_pixmap"; private static final VersionNumber GTK_VERSION_2_14_0 = new VersionNumber(2, 14, 0); private static final VersionNumber GTK_VERSION_2_24_0 = new VersionNumber(2, 24, 0); @@ -108,23 +123,25 @@ public class SWTAccessor { } static { - Field f = null; - AccessController.doPrivileged(new PrivilegedAction() { public Object run() { NativeWindowFactory.initSingleton(); // last resort .. return null; } } ); - final String nwt = NativeWindowFactory.getNativeWindowType(false); - - if(NativeWindowFactory.TYPE_MACOSX != nwt ) { + nwt = NativeWindowFactory.getNativeWindowType(false); + isOSX = NativeWindowFactory.TYPE_MACOSX == nwt; + isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt; + isX11 = NativeWindowFactory.TYPE_X11 == nwt; + + Field f = null; + if( !isOSX ) { try { f = Control.class.getField(str_handle); } catch (Exception ex) { throw new NativeWindowException(ex); } - } + } swt_control_handle = f; // maybe null ! boolean ulh; @@ -158,31 +175,32 @@ public class SWTAccessor { Class c=null; VersionNumber _gtk_version = new VersionNumber(0, 0, 0); - Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null; - Class handleType = swt_uses_long_handles ? long.class : int.class ; - if( NativeWindowFactory.TYPE_X11 == nwt ) { + Method m1=null, m2=null, m3=null, m4=null, m5=null, m6=null, m7=null, m8=null, m9=null, ma=null; + final Class handleType = swt_uses_long_handles ? long.class : int.class ; + if( isX11 ) { // mandatory try { c = ReflectionUtil.getClass(str_OS_gtk_class, false, SWTAccessor.class.getClassLoader()); Field field_OS_gtk_version = c.getField(str_OS_gtk_version); _gtk_version = GTK_VERSION(field_OS_gtk_version.getInt(null)); m1 = c.getDeclaredMethod(str_gtk_widget_realize, handleType); - if( _gtk_version.compareTo(GTK_VERSION_2_14_0) < 0 ) { - m3 = c.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType); - } else { + if (_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) { m4 = c.getDeclaredMethod(str_gtk_widget_get_window, handleType); - } - if( _gtk_version.compareTo(GTK_VERSION_2_24_0) < 0 ) { - m5 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType); } else { + m3 = c.getDeclaredMethod(str_GTK_WIDGET_WINDOW, handleType); + } + if (_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) { m6 = c.getDeclaredMethod(str_gdk_x11_display_get_xdisplay, handleType); - m7 = c.getDeclaredMethod(str_gdk_window_get_display, handleType); - } - if( _gtk_version.compareTo(GTK_VERSION_3_0_0) < 0 ) { - m8 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType); + m7 = c.getDeclaredMethod(str_gdk_window_get_display, handleType); } else { + m5 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xdisplay, handleType); + } + if (_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) { m9 = c.getDeclaredMethod(str_gdk_x11_window_get_xid, handleType); + } else { + m8 = c.getDeclaredMethod(str_gdk_x11_drawable_get_xid, handleType); } + ma = c.getDeclaredMethod(str_gdk_window_set_back_pixmap, handleType, handleType, boolean.class); } catch (Exception ex) { throw new NativeWindowException(ex); } // optional try { @@ -200,25 +218,31 @@ public class SWTAccessor { OS_gdk_window_get_display = m7; OS_gdk_x11_drawable_get_xid = m8; OS_gdk_x11_window_get_xid = m9; + OS_gdk_window_set_back_pixmap = ma; + + isX11GTK = isX11 && null != OS_gtk_class; if(DEBUG) { System.err.println("SWTAccessor.: GTK Version: "+OS_gtk_version); } } - - - static Object getIntOrLong(long arg) { + + private static Number getIntOrLong(long arg) { if(swt_uses_long_handles) { return new Long(arg); } return new Integer((int) arg); } - static void callStaticMethodL2V(Method m, long arg) { + private static void callStaticMethodL2V(Method m, long arg) { ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); } - static long callStaticMethodL2L(Method m, long arg) { + private static void callStaticMethodLLZ2V(Method m, long arg0, long arg1, boolean arg3) { + ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg0), getIntOrLong(arg1), Boolean.valueOf(arg3) }); + } + + private static long callStaticMethodL2L(Method m, long arg) { Object o = ReflectionUtil.callMethod(null, m, new Object[] { getIntOrLong(arg) }); if(o instanceof Number) { return ((Number)o).longValue(); @@ -226,13 +250,73 @@ public class SWTAccessor { throw new InternalError("SWT method "+m.getName()+" didn't return int or long but "+o.getClass()); } } - + + // + // Public properties + // + public static boolean isUsingLongHandles() { return swt_uses_long_handles; } + public static boolean useX11GTK() { return isX11GTK; } public static VersionNumber GTK_VERSION() { return OS_gtk_version; } + // + // Common GTK + // + + public static long gdk_widget_get_window(long handle) { + final long window; + if (OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0) { + window = callStaticMethodL2L(OS_gtk_widget_get_window, handle); + } else { + window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); + } + if(0 == window) { + throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle)); + } + return window; + } + + public static long gdk_window_get_xdisplay(long window) { + final long xdisplay; + if (OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0) { + final long display = callStaticMethodL2L(OS_gdk_window_get_display, window); + if(0 == display) { + throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display); + } else { + xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window); + } + if(0 == xdisplay) { + throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + return xdisplay; + } + + public static long gdk_window_get_xwindow(long window) { + final long xWindow; + if (OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0) { + xWindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window); + } else { + xWindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window); + } + if(0 == xWindow) { + throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window)); + } + return xWindow; + } + + public static void gdk_window_set_back_pixmap(long window, long pixmap, boolean parent_relative) { + callStaticMethodLLZ2V(OS_gdk_window_set_back_pixmap, window, pixmap, parent_relative); + } + + // + // Common any toolkit + // + /** * @param swtControl the SWT Control to retrieve the native widget-handle from * @return the native widget-handle @@ -240,15 +324,21 @@ public class SWTAccessor { */ public static long getHandle(Control swtControl) throws NativeWindowException { long h = 0; - if(NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false) ) { - try { - Field fView = Control.class.getField(str_view); - Object view = fView.get(swtControl); - Field fId = view.getClass().getField(str_id); - h = fId.getLong(view); - } catch (Exception ex) { - throw new NativeWindowException(ex); - } + if( isOSX ) { + synchronized(swt_osx_init) { + try { + if(null == swt_osx_view_id) { + swt_osx_control_view = Control.class.getField(str_osx_view); + Object view = swt_osx_control_view.get(swtControl); + swt_osx_view_id = view.getClass().getField(str_osx_id); + h = swt_osx_view_id.getLong(view); + } else { + h = swt_osx_view_id.getLong( swt_osx_control_view.get(swtControl) ); + } + } catch (Exception ex) { + throw new NativeWindowException(ex); + } + } } else { try { h = swt_control_handle.getLong(swtControl); @@ -283,49 +373,6 @@ public class SWTAccessor { } } - private static long gdk_x11_display_get_xdisplay(long window) { - final long xdisplay; - if ( OS_gtk_version.compareTo(GTK_VERSION_2_24_0) >= 0 ) { - final long display = callStaticMethodL2L(OS_gdk_window_get_display, window); - if(0 == display) { - throw new NativeWindowException("Null display-handle of gtk-window-handle 0x"+Long.toHexString(window)); - } - xdisplay = callStaticMethodL2L(OS_gdk_x11_display_get_xdisplay, display); - } else { - xdisplay = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, window); - } - if(0 == xdisplay) { - throw new NativeWindowException("Null x11-display-handle of gtk-window-handle 0x"+Long.toHexString(window)); - } - return xdisplay; - } - - private static long gdk_widget_get_window(long handle) { - final long window; - if ( OS_gtk_version.compareTo(GTK_VERSION_2_14_0) >= 0 ) { - window = callStaticMethodL2L(OS_gtk_widget_get_window, handle); - } else { - window = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); - } - if(0 == window) { - throw new NativeWindowException("Null gtk-window-handle of SWT handle 0x"+Long.toHexString(handle)); - } - return window; - } - - private static long gdk_window_get_xwindow(long window) { - final long xwindow; - if ( OS_gtk_version.compareTo(GTK_VERSION_3_0_0) >= 0 ) { - xwindow = callStaticMethodL2L(OS_gdk_x11_window_get_xid, window); - } else { - xwindow = callStaticMethodL2L(OS_gdk_x11_drawable_get_xid, window); - } - if(0 == xwindow) { - throw new NativeWindowException("Null x11-window-handle of gtk-window-handle 0x"+Long.toHexString(window)); - } - return xwindow; - } - /** * @param swtControl the SWT Control to retrieve the native device handle from * @return the AbstractGraphicsDevice w/ the native device handle @@ -333,43 +380,49 @@ public class SWTAccessor { * @throws UnsupportedOperationException if the windowing system is not supported */ public static AbstractGraphicsDevice getDevice(Control swtControl) throws NativeWindowException, UnsupportedOperationException { - long handle = getHandle(swtControl); - if( null != OS_gtk_class ) { - final long xdisplay0 = gdk_x11_display_get_xdisplay( gdk_widget_get_window( handle ) ); - // final String displayName = X11Lib.XDisplayString(xdisplay0); - // final long xdisplay1 = X11Util.openDisplay(displayName); - // return new X11GraphicsDevice(xdisplay1, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); + final long handle = getHandle(swtControl); + if( isX11GTK ) { + final long xdisplay0 = gdk_window_get_xdisplay( gdk_widget_get_window( handle ) ); return new X11GraphicsDevice(xdisplay0, AbstractGraphicsDevice.DEFAULT_UNIT, false /* owner */); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + if( isWindows ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); } - if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isOSX ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } + /** + * + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return + * @throws UnsupportedOperationException + */ public static AbstractGraphicsScreen getScreen(AbstractGraphicsDevice device, int screen) throws UnsupportedOperationException { - if( null != OS_gtk_class ) { - return new X11GraphicsScreen((X11GraphicsDevice)device, screen); + if( isX11 ) { + X11GraphicsDevice x11Device = (X11GraphicsDevice)device; + if(0 > screen) { + screen = x11Device.getDefaultScreen(); + } + return new X11GraphicsScreen(x11Device, screen); + } + if(0 > screen) { + screen = 0; // FIXME: Needs native API utilization } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return new DefaultGraphicsScreen(device, screen); } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); } public static int getNativeVisualID(AbstractGraphicsDevice device, long windowHandle) { - if( null != OS_gtk_class ) { + if( isX11 ) { return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return VisualIDHolder.VID_UNDEFINED; } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); @@ -383,12 +436,13 @@ public class SWTAccessor { */ public static long getWindowHandle(Control swtControl) throws NativeWindowException, UnsupportedOperationException { final long handle = getHandle(swtControl); - if( null != OS_gtk_class ) { + if(0 == handle) { + throw new NativeWindowException("Null SWT handle of SWT control "+swtControl); + } + if( isX11GTK ) { return gdk_window_get_xwindow( gdk_widget_get_window( handle ) ); } - final String nwt = NativeWindowFactory.getNativeWindowType(false); - if( NativeWindowFactory.TYPE_WINDOWS == nwt || - NativeWindowFactory.TYPE_MACOSX == nwt ) { + if( isWindows || isOSX ) { return handle; } throw new UnsupportedOperationException("n/a for this windowing system: "+nwt); @@ -407,7 +461,7 @@ public class SWTAccessor { throw new InternalError("SWT internal_new_GC did not return int or long but "+o[0].getClass()); } } - + public static void disposeGC(final Control swtControl, final long gc, final GCData gcData) { invoke(true, new Runnable() { public void run() { @@ -437,7 +491,7 @@ public class SWTAccessor { * @see Platform#getOSType() */ public static void invoke(boolean wait, Runnable runnable) { - if( Platform.OS_TYPE == Platform.OSType.MACOS ) { + if( isOSX ) { // Use SWT main thread! Only reliable config w/ -XStartOnMainThread !? OSXUtil.RunOnMainThread(wait, runnable); } else { @@ -445,4 +499,85 @@ public class SWTAccessor { } } + // + // Specific X11 GTK ChildWindow - Using plain X11 native parenting (works well) + // + + public static long createCompatibleX11ChildWindow(AbstractGraphicsScreen screen, Control swtControl, int visualID, int width, int height) { + final long handle = getHandle(swtControl); + final long parentWindow = gdk_widget_get_window( handle ); + gdk_window_set_back_pixmap (parentWindow, 0, false); + + final long x11ParentHandle = gdk_window_get_xwindow(parentWindow); + final long x11WindowHandle = X11Lib.CreateWindow(x11ParentHandle, screen.getDevice().getHandle(), screen.getIndex(), visualID, width, height, true, true); + + return x11WindowHandle; + } + + public static void resizeX11Window(AbstractGraphicsDevice device, Rectangle clientArea, long x11Window) { + X11Lib.SetWindowPosSize(device.getHandle(), x11Window, clientArea.x, clientArea.y, clientArea.width, clientArea.height); + } + public static void destroyX11Window(AbstractGraphicsDevice device, long x11Window) { + X11Lib.DestroyWindow(device.getHandle(), x11Window); + } + + // + // Specific X11 SWT/GTK ChildWindow - Using SWT/GTK native parenting (buggy - sporadic resize flickering, sporadic drop of rendering) + // + // FIXME: Need to use reflection for 32bit access as well ! + // + + // public static final int GDK_WA_TYPE_HINT = 1 << 9; + // public static final int GDK_WA_VISUAL = 1 << 6; + + public static long createCompatibleGDKChildWindow(Control swtControl, int visualID, int width, int height) { + return 0; + /** + final long handle = SWTAccessor.getHandle(swtControl); + final long parentWindow = gdk_widget_get_window( handle ); + + final long screen = OS.gdk_screen_get_default (); + final long gdkvisual = OS.gdk_x11_screen_lookup_visual (screen, visualID); + + final GdkWindowAttr attrs = new GdkWindowAttr(); + attrs.width = width > 0 ? width : 1; + attrs.height = height > 0 ? height : 1; + attrs.event_mask = OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK | + OS.GDK_FOCUS_CHANGE_MASK | OS.GDK_POINTER_MOTION_MASK | + OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK | + OS.GDK_ENTER_NOTIFY_MASK | OS.GDK_LEAVE_NOTIFY_MASK | + OS.GDK_EXPOSURE_MASK | OS.GDK_VISIBILITY_NOTIFY_MASK | + OS.GDK_POINTER_MOTION_HINT_MASK; + attrs.window_type = OS.GDK_WINDOW_CHILD; + attrs.visual = gdkvisual; + + final long childWindow = OS.gdk_window_new (parentWindow, attrs, OS.GDK_WA_VISUAL|GDK_WA_TYPE_HINT); + OS.gdk_window_set_user_data (childWindow, handle); + OS.gdk_window_set_back_pixmap (parentWindow, 0, false); + + OS.gdk_window_show (childWindow); + OS.gdk_flush(); + return childWindow; */ + } + + public static void showGDKWindow(long gdkWindow) { + /* OS.gdk_window_show (gdkWindow); + OS.gdk_flush(); */ + } + public static void focusGDKWindow(long gdkWindow) { + /* + OS.gdk_window_show (gdkWindow); + OS.gdk_window_focus(gdkWindow, 0); + OS.gdk_flush(); */ + } + public static void resizeGDKWindow(Rectangle clientArea, long gdkWindow) { + /** + OS.gdk_window_move (gdkWindow, clientArea.x, clientArea.y); + OS.gdk_window_resize (gdkWindow, clientArea.width, clientArea.height); + OS.gdk_flush(); */ + } + + public static void destroyGDKWindow(long gdkWindow) { + // OS.gdk_window_destroy (gdkWindow); + } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java index 67a33e55c..827862002 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java @@ -37,7 +37,7 @@ public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); } if( 0 == s.getSurfaceHandle() ) { - final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64); + final long windowHandle = X11Lib.CreateWindow(0, device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64, false, false); if(0 == windowHandle) { throw new NativeWindowException("Creating dummy window failed w/ "+cfg); } @@ -59,7 +59,7 @@ public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize } device.lock(); try { - X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle()); + X11Lib.DestroyWindow(device.getHandle(), s.getSurfaceHandle()); s.setSurfaceHandle(0); s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } finally { diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index c73952693..a8d45f288 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -31,6 +31,8 @@ #include "jogamp_nativewindow_x11_X11Lib.h" #include "jogamp_nativewindow_x11_X11Util.h" +#include + // #define VERBOSE_ON 1 #ifdef VERBOSE_ON @@ -85,6 +87,8 @@ Bool XF86VidModeSetGammaRamp( #define RTLD_DEFAULT NULL #endif +#define X11_MOUSE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask) + static const char * const ClazzNameBuffers = "com/jogamp/common/nio/Buffers"; static const char * const ClazzNameBuffersStaticCstrName = "copyByteBuffer"; static const char * const ClazzNameBuffersStaticCstrSignature = "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"; @@ -436,17 +440,62 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused return _res; } +static void NativewindowX11_setNormalWindowEWMH (Display *dpy, Window w) { + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[1]={0}; + types[0] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1); + XSync(dpy, False); +} + +#define DECOR_USE_MWM 1 // works for known WMs +// #define DECOR_USE_EWMH 1 // haven't seen this to work (NORMAL->POPUP, never gets undecorated) + +/* see */ +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 + +static void NativewindowX11_setDecorations (Display *dpy, Window w, Bool decorated) { + +#ifdef DECOR_USE_MWM + unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status + Atom _MOTIF_WM_HINTS = XInternAtom( dpy, "_MOTIF_WM_HINTS", False ); +#endif + +#ifdef DECOR_USE_EWMH + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[3]={0}; + int ntypes=0; + if(True==decorated) { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + } else { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False ); + } +#endif + +#ifdef DECOR_USE_MWM + XChangeProperty( dpy, w, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS); +#endif + +#ifdef DECOR_USE_EWMH + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); +#endif + + XSync(dpy, False); +} + /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: CreateDummyWindow - * Signature: (JIIII)J + * Method: CreateWindow + * Signature: (JJIIIIZZ)J */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow - (JNIEnv *env, jclass unused, jlong display, jint screen_index, jint visualID, jint width, jint height) +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow + (JNIEnv *env, jclass unused, jlong parent, jlong display, jint screen_index, jint visualID, jint width, jint height, jboolean input, jboolean visible) { Display * dpy = (Display *)(intptr_t)display; int scrn_idx = (int)screen_index; - Window windowParent = 0; + Window root = RootWindow(dpy, scrn_idx); + Window windowParent = (Window) parent; Window window = 0; XVisualInfo visualTemplate; @@ -473,6 +522,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); + if(0==windowParent) { + windowParent = root; + } // try given VisualID on screen memset(&visualTemplate, 0, sizeof(XVisualInfo)); @@ -500,9 +552,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow pVisualQuery=NULL; } - if(0==windowParent) { - windowParent = XRootWindowOfScreen(scrn); - } attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap | CWBorderPixel | CWColormap | CWOverrideRedirect ) ; @@ -514,15 +563,22 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow xswa.backing_store=NotUseful; /* NotUseful, WhenMapped, Always */ xswa.backing_planes=0; /* planes to be preserved if possible */ xswa.backing_pixel=0; /* value to use in restoring planes */ + if( input ) { + xswa.event_mask = X11_MOUSE_EVENT_MASK; + xswa.event_mask |= KeyPressMask | KeyReleaseMask ; + } + if( visible ) { + xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ; + } xswa.colormap = XCreateColormap(dpy, - XRootWindow(dpy, scrn_idx), + windowParent, visual, AllocNone); window = XCreateWindow(dpy, windowParent, - 0, 0, + 0, 0, // only a hint, WM most likely will override width, height, 0, // border width depth, @@ -530,9 +586,25 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow visual, attrMask, &xswa); + if(0==window) { + NativewindowCommon_throwNewRuntimeException(env, "could not create Window, bail out!"); + return 0; + } + + NativewindowX11_setNormalWindowEWMH(dpy, window); + NativewindowX11_setDecorations(dpy, window, False); + + if( visible ) { + XEvent event; + + XMapWindow(dpy, window); + } + XSync(dpy, False); - XSelectInput(dpy, window, 0); // no events + if( !input ) { + XSelectInput(dpy, window, 0); // no events + } // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); @@ -544,10 +616,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: DestroyDummyWindow + * Method: DestroyWindow * Signature: (JJ)V */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow (JNIEnv *env, jclass unused, jlong display, jlong window) { Display * dpy = (Display *)(intptr_t)display; @@ -559,12 +631,37 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow } NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, 0, 0); + XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0, 1); } +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize + (JNIEnv *env, jclass unused, jlong display, jlong window, jint x, jint y, jint width, jint height) { + Display * dpy = (Display *)(intptr_t)display; + Window w = (Window) window; + XWindowChanges xwc; + int flags = 0; + + memset(&xwc, 0, sizeof(XWindowChanges)); + + if(0<=x && 0<=y) { + flags |= CWX | CWY; + xwc.x=x; + xwc.y=y; + } + + if(0 + * Implementation allows use of custom {@link GLCapabilities}. + *

    */ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { private static final boolean DEBUG = Debug.debug("Window"); @@ -126,54 +126,44 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { clientArea = getClientArea(); final AbstractGraphicsDevice device = SWTAccessor.getDevice(this); - screen = SWTAccessor.getScreen(device, 0); + screen = SWTAccessor.getScreen(device, -1 /* default */); nativeWindow = null; if(null != child) { setNEWTChild(child); } - - /* Register SWT listeners (e.g. PaintListener) to render/resize GL surface. */ - /* TODO: verify that these do not need to be manually de-registered when destroying the SWT component */ - addPaintListener(new PaintListener() { + + final Listener listener = new Listener () { @Override - public void paintControl(final PaintEvent arg0) { - if( null != nativeWindow || validateNative() ) { - if( newtChildReady ) { - if( postSetSize ) { - newtChild.setSize(clientArea.width, clientArea.height); - postSetSize = false; + public void handleEvent (Event event) { + switch (event.type) { + case SWT.Paint: + if( null != nativeWindow || validateNative() ) { + if( newtChildReady ) { + if( postSetSize ) { + newtChild.setSize(clientArea.width, clientArea.height); + postSetSize = false; + } + newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height); } - newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height); } + break; + case SWT.Resize: + updateSizeCheck(); + break; + case SWT.Dispose: + NewtCanvasSWT.this.dispose(); + break; } } - }); - - addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - @Override - public void controlResized(final ControlEvent arg0) { - updateSizeCheck(); - } - }); - - addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - NewtCanvasSWT.this.dispose(); - } - }); - + }; + addListener (SWT.Resize, listener); + addListener (SWT.Paint, listener); + addListener (SWT.Dispose, listener); } /** assumes nativeWindow == null ! */ protected final boolean validateNative() { - if( isDisposed() || !isVisible() ) { - return false; - } updateSizeCheck(); final Rectangle nClientArea = clientArea; if(0 >= nClientArea.width || 0 >= nClientArea.height) { @@ -216,6 +206,10 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { ( nClientArea.width != oClientArea.width || nClientArea.height != oClientArea.height ) ) { clientArea = nClientArea; // write back new value + if(DEBUG) { + final long nsh = newtChildReady ? newtChild.getSurfaceHandle() : 0; + System.err.println("NewtCanvasSWT.sizeChanged: ("+Thread.currentThread().getName()+"): newtChildReady "+newtChildReady+", "+nClientArea.x+"/"+nClientArea.y+" "+nClientArea.width+"x"+nClientArea.height+" - surfaceHandle 0x"+Long.toHexString(nsh)); + } if( newtChildReady ) { newtChild.setSize(clientArea.width, clientArea.height); } else { @@ -223,7 +217,7 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { } } } - + @Override public void update() { // don't paint background etc .. nop avoids flickering @@ -261,11 +255,11 @@ public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { public NativeWindow getNativeWindow() { return nativeWindow; } public WindowClosingMode getDefaultCloseOperation() { - return newtChildCloseOp; // FIXME + return newtChildCloseOp; // TODO: implement ?! } public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) { - return newtChildCloseOp = op; // FIXME + return newtChildCloseOp = op; // TODO: implement ?! } diff --git a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java deleted file mode 100644 index 1c20fe524..000000000 --- a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java +++ /dev/null @@ -1,313 +0,0 @@ -/** - * Copyright 2012 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.newt.swt; - -import javax.media.nativewindow.NativeWindowException; - -import jogamp.newt.Debug; - -import com.jogamp.common.util.RunnableTask; -import com.jogamp.newt.util.EDTUtil; - -/** - * Simple {@link EDTUtil} implementation utilizing the SWT UI thread - * of the given {@link Display}. - */ -public class SWTEDTUtil implements EDTUtil { - public static final boolean DEBUG = Debug.debug("EDT"); - - private final Object edtLock = new Object(); // locking the EDT start/stop state - private final ThreadGroup threadGroup; - private final String name; - private final Runnable dispatchMessages; - private final org.eclipse.swt.widgets.Display swtDisplay; - private NewtEventDispatchThread nedt = null; - private int start_iter=0; - private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; - - public SWTEDTUtil(final com.jogamp.newt.Display newtDisplay, org.eclipse.swt.widgets.Display swtDisplay) { - this.threadGroup = Thread.currentThread().getThreadGroup(); - this.name=Thread.currentThread().getName()+"-SWTDisplay-"+newtDisplay.getFQName()+"-EDT-"; - this.dispatchMessages = new Runnable() { - public void run() { - ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages(); - } }; - this.swtDisplay = swtDisplay; - this.nedt = new NewtEventDispatchThread(threadGroup, name); - this.nedt.setDaemon(true); // don't stop JVM from shutdown .. - } - - public final org.eclipse.swt.widgets.Display getDisplay() { - return swtDisplay; - } - - @Override - public long getPollPeriod() { - return pollPeriod; - } - - @Override - public void setPollPeriod(long ms) { - pollPeriod = ms; - } - - @Override - public void reset() { - synchronized(edtLock) { - waitUntilStopped(); - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt); - } - this.nedt = new NewtEventDispatchThread(threadGroup, name); - this.nedt.setDaemon(true); // don't stop JVM from shutdown .. - } - } - - private final void startImpl() { - if(nedt.isAlive()) { - throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); - } - start_iter++; - nedt.setName(name+start_iter); - nedt.shouldStop = false; - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT START - edt: "+nedt); - // Thread.dumpStack(); - } - nedt.start(); - } - - @Override - public boolean isCurrentThreadEDT() { - return swtDisplay.getThread() == Thread.currentThread(); - } - - @Override - public final boolean isCurrentThreadNEDT() { - return nedt == Thread.currentThread(); - } - - @Override - public final boolean isCurrentThreadEDTorNEDT() { - final Thread ct = Thread.currentThread(); - return ct == swtDisplay.getThread() || ct == nedt ; - } - - @Override - public boolean isRunning() { - return nedt.isRunning() ; // SWT is always running - } - - @Override - public final void invokeStop(Runnable task) { - invokeImpl(true, task, true); - } - - @Override - public final void invoke(boolean wait, Runnable task) { - invokeImpl(wait, task, false); - } - - private void invokeImpl(boolean wait, Runnable task, boolean stop) { - Throwable throwable = null; - RunnableTask rTask = null; - Object rTaskLock = new Object(); - synchronized(rTaskLock) { // lock the optional task execution - synchronized(edtLock) { // lock the EDT status - if( nedt.shouldStop ) { - // drop task .. - if(DEBUG) { - System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt); - Thread.dumpStack(); - } - return; - } - // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); - // Thread.dumpStack(); - if(stop) { - synchronized(nedt.sync) { - nedt.shouldStop = true; - nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) - } - if(DEBUG) { - System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); - // Thread.dumpStack(); - } - } else if( !nedt.isRunning() ) { - // start if should not stop && not started yet - startImpl(); - } - if( null == task ) { - wait = false; - } else if( isCurrentThreadEDT() ) { - task.run(); - wait = false; // running in same thread (EDT) -> no wait - } else if( swtDisplay.isDisposed() ) { - wait = false; // drop task, SWT disposed - } else { - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - true /* always catch and report Exceptions, don't disturb EDT */); - swtDisplay.asyncExec(rTask); - } - } - if( wait ) { - try { - rTaskLock.wait(); // free lock, allow execution of rTask - } catch (InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rTask.getThrowable(); - } - if(null!=throwable) { - if(throwable instanceof NativeWindowException) { - throw (NativeWindowException)throwable; - } - throw new RuntimeException(throwable); - } - } - } - } - - @Override - final public void waitUntilIdle() { - final NewtEventDispatchThread _nedt; - synchronized(edtLock) { - _nedt = nedt; - } - final Thread ct = Thread.currentThread(); - if(!_nedt.isRunning() || _nedt == ct || swtDisplay.getThread() == ct) { - return; - } - try { - swtDisplay.syncExec(new Runnable() { - public void run() { } - }); - } catch (Exception e) { } - } - - @Override - final public void waitUntilStopped() { - synchronized(edtLock) { - final Thread ct = Thread.currentThread(); - if(nedt.isRunning() && nedt != ct && swtDisplay.getThread() != ct) { - while(nedt.isRunning()) { - try { - edtLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - } - - class NewtEventDispatchThread extends Thread { - volatile boolean shouldStop = false; - volatile boolean isRunning = false; - Object sync = new Object(); - - public NewtEventDispatchThread(ThreadGroup tg, String name) { - super(tg, name); - } - - final public boolean isRunning() { - return isRunning; - } - - @Override - final public void start() throws IllegalThreadStateException { - isRunning = true; - super.start(); - } - - /** - * Utilizing locking only on tasks and its execution, - * not for event dispatching. - */ - @Override - final public void run() { - if(DEBUG) { - System.err.println(getName()+": SWT-EDT run() START "+ getName()); - } - RuntimeException error = null; - try { - do { - // event dispatch - if(!shouldStop) { - // EDT invoke thread is SWT-EDT, - // hence dispatching is required to run on SWT-EDT as well. - // Otherwise a deadlock may happen due to dispatched event's - // triggering a locking action. - if ( !swtDisplay.isDisposed() ) { - swtDisplay.syncExec(dispatchMessages); - } else { - dispatchMessages.run(); - } - } - // wait - synchronized(sync) { - if(!shouldStop) { - try { - sync.wait(pollPeriod); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } while(!shouldStop) ; - } catch (Throwable t) { - // handle errors .. - shouldStop = true; - if(t instanceof RuntimeException) { - error = (RuntimeException) t; - } else { - error = new RuntimeException("Within SWT-EDT", t); - } - } finally { - if(DEBUG) { - System.err.println(getName()+": SWT-EDT run() END "+ getName()+", "+error); - } - synchronized(edtLock) { - isRunning = !shouldStop; - if(!isRunning) { - edtLock.notifyAll(); - } - } - if(DEBUG) { - System.err.println(getName()+": SWT-EDT run() EXIT "+ getName()+", exception: "+error); - } - if(null!=error) { - throw error; - } - } // finally - } // run() - } // EventDispatchThread - -} diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java new file mode 100644 index 000000000..7297e5858 --- /dev/null +++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java @@ -0,0 +1,313 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.newt.swt; + +import javax.media.nativewindow.NativeWindowException; + +import jogamp.newt.Debug; + +import com.jogamp.common.util.RunnableTask; +import com.jogamp.newt.util.EDTUtil; + +/** + * Simple {@link EDTUtil} implementation utilizing the SWT UI thread + * of the given {@link Display}. + */ +public class SWTEDTUtil implements EDTUtil { + public static final boolean DEBUG = Debug.debug("EDT"); + + private final Object edtLock = new Object(); // locking the EDT start/stop state + private final ThreadGroup threadGroup; + private final String name; + private final Runnable dispatchMessages; + private final org.eclipse.swt.widgets.Display swtDisplay; + private NewtEventDispatchThread nedt = null; + private int start_iter=0; + private static long pollPeriod = EDTUtil.defaultEDTPollPeriod; + + public SWTEDTUtil(final com.jogamp.newt.Display newtDisplay, org.eclipse.swt.widgets.Display swtDisplay) { + this.threadGroup = Thread.currentThread().getThreadGroup(); + this.name=Thread.currentThread().getName()+"-SWTDisplay-"+newtDisplay.getFQName()+"-EDT-"; + this.dispatchMessages = new Runnable() { + public void run() { + ((jogamp.newt.DisplayImpl) newtDisplay).dispatchMessages(); + } }; + this.swtDisplay = swtDisplay; + this.nedt = new NewtEventDispatchThread(threadGroup, name); + this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + + public final org.eclipse.swt.widgets.Display getDisplay() { + return swtDisplay; + } + + @Override + public long getPollPeriod() { + return pollPeriod; + } + + @Override + public void setPollPeriod(long ms) { + pollPeriod = ms; + } + + @Override + public void reset() { + synchronized(edtLock) { + waitUntilStopped(); + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT reset - edt: "+nedt); + } + this.nedt = new NewtEventDispatchThread(threadGroup, name); + this.nedt.setDaemon(true); // don't stop JVM from shutdown .. + } + } + + private final void startImpl() { + if(nedt.isAlive()) { + throw new RuntimeException("SWT-EDT Thread.isAlive(): true, isRunning: "+nedt.isRunning()+", edt: "+nedt); + } + start_iter++; + nedt.setName(name+start_iter); + nedt.shouldStop = false; + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT START - edt: "+nedt); + // Thread.dumpStack(); + } + nedt.start(); + } + + @Override + public boolean isCurrentThreadEDT() { + return swtDisplay.getThread() == Thread.currentThread(); + } + + @Override + public final boolean isCurrentThreadNEDT() { + return nedt == Thread.currentThread(); + } + + @Override + public final boolean isCurrentThreadEDTorNEDT() { + final Thread ct = Thread.currentThread(); + return ct == swtDisplay.getThread() || ct == nedt ; + } + + @Override + public boolean isRunning() { + return nedt.isRunning() ; // SWT is always running + } + + @Override + public final void invokeStop(Runnable task) { + invokeImpl(true, task, true); + } + + @Override + public final void invoke(boolean wait, Runnable task) { + invokeImpl(wait, task, false); + } + + private void invokeImpl(boolean wait, Runnable task, boolean stop) { + Throwable throwable = null; + RunnableTask rTask = null; + Object rTaskLock = new Object(); + synchronized(rTaskLock) { // lock the optional task execution + synchronized(edtLock) { // lock the EDT status + if( nedt.shouldStop ) { + // drop task .. + if(DEBUG) { + System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt); + Thread.dumpStack(); + } + return; + } + // System.err.println(Thread.currentThread()+" XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); + // Thread.dumpStack(); + if(stop) { + synchronized(nedt.sync) { + nedt.shouldStop = true; + nedt.sync.notifyAll(); // stop immediate if waiting (poll freq) + } + if(DEBUG) { + System.err.println(Thread.currentThread()+": SWT-EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - "+nedt); + // Thread.dumpStack(); + } + } else if( !nedt.isRunning() ) { + // start if should not stop && not started yet + startImpl(); + } + if( null == task ) { + wait = false; + } else if( isCurrentThreadEDT() ) { + task.run(); + wait = false; // running in same thread (EDT) -> no wait + } else if( swtDisplay.isDisposed() ) { + wait = false; // drop task, SWT disposed + } else { + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */); + swtDisplay.asyncExec(rTask); + } + } + if( wait ) { + try { + rTaskLock.wait(); // free lock, allow execution of rTask + } catch (InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rTask.getThrowable(); + } + if(null!=throwable) { + if(throwable instanceof NativeWindowException) { + throw (NativeWindowException)throwable; + } + throw new RuntimeException(throwable); + } + } + } + } + + @Override + final public void waitUntilIdle() { + final NewtEventDispatchThread _nedt; + synchronized(edtLock) { + _nedt = nedt; + } + final Thread ct = Thread.currentThread(); + if(!_nedt.isRunning() || _nedt == ct || swtDisplay.getThread() == ct) { + return; + } + try { + swtDisplay.syncExec(new Runnable() { + public void run() { } + }); + } catch (Exception e) { } + } + + @Override + final public void waitUntilStopped() { + synchronized(edtLock) { + final Thread ct = Thread.currentThread(); + if(nedt.isRunning() && nedt != ct && swtDisplay.getThread() != ct) { + while(nedt.isRunning()) { + try { + edtLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + + class NewtEventDispatchThread extends Thread { + volatile boolean shouldStop = false; + volatile boolean isRunning = false; + Object sync = new Object(); + + public NewtEventDispatchThread(ThreadGroup tg, String name) { + super(tg, name); + } + + final public boolean isRunning() { + return isRunning; + } + + @Override + final public void start() throws IllegalThreadStateException { + isRunning = true; + super.start(); + } + + /** + * Utilizing locking only on tasks and its execution, + * not for event dispatching. + */ + @Override + final public void run() { + if(DEBUG) { + System.err.println(getName()+": SWT-EDT run() START "+ getName()); + } + RuntimeException error = null; + try { + do { + // event dispatch + if(!shouldStop) { + // EDT invoke thread is SWT-EDT, + // hence dispatching is required to run on SWT-EDT as well. + // Otherwise a deadlock may happen due to dispatched event's + // triggering a locking action. + if ( !swtDisplay.isDisposed() ) { + swtDisplay.syncExec(dispatchMessages); + } else { + dispatchMessages.run(); + } + } + // wait + synchronized(sync) { + if(!shouldStop) { + try { + sync.wait(pollPeriod); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } while(!shouldStop) ; + } catch (Throwable t) { + // handle errors .. + shouldStop = true; + if(t instanceof RuntimeException) { + error = (RuntimeException) t; + } else { + error = new RuntimeException("Within SWT-EDT", t); + } + } finally { + if(DEBUG) { + System.err.println(getName()+": SWT-EDT run() END "+ getName()+", "+error); + } + synchronized(edtLock) { + isRunning = !shouldStop; + if(!isRunning) { + edtLock.notifyAll(); + } + } + if(DEBUG) { + System.err.println(getName()+": SWT-EDT run() EXIT "+ getName()+", exception: "+error); + } + if(null!=error) { + throw error; + } + } // finally + } // run() + } // EventDispatchThread + +} diff --git a/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java new file mode 100644 index 000000000..e238f5d9e --- /dev/null +++ b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java @@ -0,0 +1,249 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.newt.swt.event; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.newt.event.InputEvent; + +/** + * SWT event translator to NEWT, inclusive dispatch listener. + *

    + * Disclaimer: This code is merely tested and subject to change. + *

    + */ +public class SWTNewtEventFactory { + + protected static final IntIntHashMap eventTypeSWT2NEWT; + + static { + IntIntHashMap map = new IntIntHashMap(); + map.setKeyNotFoundValue(0xFFFFFFFF); + + // map.put(SWT.MouseXXX, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED); + map.put(SWT.MouseDown, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED); + map.put(SWT.MouseUp, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED); + map.put(SWT.MouseMove, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED); + map.put(SWT.MouseEnter, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_ENTERED); + map.put(SWT.MouseExit, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_EXITED); + // map.put(SWT.MouseXXX, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED); + map.put(SWT.MouseVerticalWheel, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED); + + map.put(SWT.KeyDown, com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED); + map.put(SWT.KeyUp, com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED); + // map.put(SWT.KeyXXX, com.jogamp.newt.event.KeyEvent.EVENT_KEY_TYPED); + + eventTypeSWT2NEWT = map; + } + + public static final int swtModifiers2Newt(int awtMods, boolean mouseHint) { + int newtMods = 0; + if ((awtMods & SWT.SHIFT) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK; + if ((awtMods & SWT.CTRL) != 0) newtMods |= com.jogamp.newt.event.InputEvent.CTRL_MASK; + if ((awtMods & SWT.ALT) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK; + return newtMods; + } + + public static final com.jogamp.newt.event.InputEvent createInputEvent(org.eclipse.swt.widgets.Event event, Object source) { + com.jogamp.newt.event.InputEvent res = createMouseEvent(event, source); + if(null == res) { + res = createKeyEvent(event, source); + } + return res; + } + + public static final com.jogamp.newt.event.MouseEvent createMouseEvent(org.eclipse.swt.widgets.Event event, Object source) { + switch(event.type) { + case SWT.MouseDown: + case SWT.MouseUp: + case SWT.MouseMove: + case SWT.MouseEnter: + case SWT.MouseExit: + case SWT.MouseVerticalWheel: + break; + default: + return null; + } + int type = eventTypeSWT2NEWT.get(event.type); + if(0xFFFFFFFF != type) { + int rotation = 0; + if (SWT.MouseVerticalWheel == event.type) { + // SWT/NEWT rotation is reversed - AWT +1 is down, NEWT +1 is up. + // rotation = -1 * (int) event.rotation; + rotation = (int) event.rotation; + } + + int mods = swtModifiers2Newt(event.stateMask, true); + + if( source instanceof com.jogamp.newt.Window) { + final com.jogamp.newt.Window newtSource = (com.jogamp.newt.Window)source; + if(newtSource.isPointerConfined()) { + mods |= InputEvent.CONFINED_MASK; + } + if(!newtSource.isPointerVisible()) { + mods |= InputEvent.INVISIBLE_MASK; + } + } + + return new com.jogamp.newt.event.MouseEvent( + type, (null==source)?(Object)event.data:source, (0xFFFFFFFFL & (long)event.time), + mods, event.x, event.y, event.count, event.button, rotation); + } + return null; // no mapping .. + } + + public static final com.jogamp.newt.event.KeyEvent createKeyEvent(org.eclipse.swt.widgets.Event event, Object source) { + switch(event.type) { + case SWT.KeyDown: + case SWT.KeyUp: + break; + default: + return null; + } + int type = eventTypeSWT2NEWT.get(event.type); + if(0xFFFFFFFF != type) { + return new com.jogamp.newt.event.KeyEvent( + type, (null==source)?(Object)event.data:source, (0xFFFFFFFFL & (long)event.time), + swtModifiers2Newt(event.stateMask, false), + event.keyCode, event.character); + } + return null; // no mapping .. + } + + // + // + // + + int dragButtonDown = 0; + + public SWTNewtEventFactory() { + resetButtonsDown(); + } + + final void resetButtonsDown() { + dragButtonDown = 0; + } + + public final boolean dispatchMouseEvent(org.eclipse.swt.widgets.Event event, Object source, com.jogamp.newt.event.MouseListener l) { + com.jogamp.newt.event.MouseEvent res = createMouseEvent(event, source); + if(null != res) { + if(null != l) { + switch(event.type) { + case SWT.MouseDown: + dragButtonDown = event.button; + l.mousePressed(res); break; + case SWT.MouseUp: + dragButtonDown = 0; + l.mouseReleased(res); + { + final com.jogamp.newt.event.MouseEvent res2 = new com.jogamp.newt.event.MouseEvent( + com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED, + res.getSource(), + res.getWhen(), res.getModifiers(), + res.getX(), res.getY(), res.getClickCount(), + res.getButton(), res.getWheelRotation() ); + l.mouseClicked(res2); + } + break; + case SWT.MouseMove: + if( 0 < dragButtonDown ) { + final com.jogamp.newt.event.MouseEvent res2 = new com.jogamp.newt.event.MouseEvent( + com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED, + res.getSource(), + res.getWhen(), res.getModifiers(), + res.getX(), res.getY(), res.getClickCount(), + dragButtonDown, res.getWheelRotation() ); + l.mouseDragged( res2 ); + } else { + l.mouseMoved(res); + } + break; + case SWT.MouseEnter: + l.mouseEntered(res); + break; + case SWT.MouseExit: + resetButtonsDown(); + l.mouseExited(res); + break; + case SWT.MouseVerticalWheel: + l.mouseWheelMoved(res); + break; + } + } + return true; + } + return false; + } + + public final boolean dispatchKeyEvent(org.eclipse.swt.widgets.Event event, Object source, com.jogamp.newt.event.KeyListener l) { + com.jogamp.newt.event.KeyEvent res = createKeyEvent(event, source); + if(null != res) { + if(null != l) { + switch(event.type) { + case SWT.KeyDown: + l.keyPressed(res); + break; + case SWT.KeyUp: + l.keyReleased(res); + l.keyTyped(res); + break; + } + } + return true; + } + return false; + } + + public final void attachDispatchListener(final org.eclipse.swt.widgets.Control ctrl, final Object source, + final com.jogamp.newt.event.MouseListener ml, + final com.jogamp.newt.event.KeyListener kl) { + final Listener listener = new Listener () { + @Override + public void handleEvent (Event event) { + if( dispatchMouseEvent( event, source, ml ) ) { + return; + } + if( dispatchKeyEvent( event, source, kl ) ) { + return; + } + } }; + ctrl.addListener(SWT.MouseDown, listener); + ctrl.addListener(SWT.MouseUp, listener); + ctrl.addListener(SWT.MouseMove, listener); + ctrl.addListener(SWT.MouseEnter, listener); + ctrl.addListener(SWT.MouseExit, listener); + ctrl.addListener(SWT.MouseVerticalWheel, listener); + ctrl.addListener(SWT.KeyDown, listener); + ctrl.addListener(SWT.KeyUp, listener); + } +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index e9fe9b401..a3023538f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -60,8 +60,8 @@ public class GearsES2 implements GLEventListener { private int swapInterval = 0; private boolean pmvUseBackingArray = true; // the default for PMVMatrix now, since it's faster // private MouseListener gearsMouse = new TraceMouseAdapter(new GearsMouseAdapter()); - private MouseListener gearsMouse = new GearsMouseAdapter(); - private KeyListener gearsKeys = new GearsKeyAdapter(); + public MouseListener gearsMouse = new GearsMouseAdapter(); + public KeyListener gearsKeys = new GearsKeyAdapter(); private int prevMouseX, prevMouseY; private boolean doRotate = true; @@ -352,6 +352,10 @@ public class GearsES2 implements GLEventListener { window = (Window) source; width=window.getWidth(); height=window.getHeight(); + } else if (source instanceof GLAutoDrawable) { + GLAutoDrawable glad = (GLAutoDrawable) source; + width = glad.getWidth(); + height = glad.getHeight(); } else if (GLProfile.isAWTAvailable() && source instanceof java.awt.Component) { java.awt.Component comp = (java.awt.Component) source; width=comp.getWidth(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java index a0874e609..1f3bf3156 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestNewtCanvasSWTBug628ResizeDeadlock.java @@ -366,8 +366,9 @@ public class TestNewtCanvasSWTBug628ResizeDeadlock extends UITestCase { try { while( !shallStop && !dsc.display.isDisposed() ) { - if( !dsc.display.readAndDispatch() ) { - dsc.display.sleep(); + if( !dsc.display.readAndDispatch() && !shallStop ) { + // blocks on linux .. dsc.display.sleep(); + Thread.sleep(10); } } } catch (Exception e0) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java index 0a47b96eb..97b3ab243 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTBug643AsyncExec.java @@ -45,12 +45,13 @@ import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities ; import javax.media.opengl.GLProfile; +import jogamp.newt.swt.SWTEDTUtil; +import jogamp.newt.swt.event.SWTNewtEventFactory; import junit.framework.Assert; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.newt.opengl.GLWindow ; import com.jogamp.newt.swt.NewtCanvasSWT ; -import com.jogamp.newt.swt.SWTEDTUtil; import com.jogamp.opengl.swt.GLCanvas; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; @@ -121,15 +122,15 @@ public class TestSWTBug643AsyncExec extends UITestCase { final Runnable swtAsyncAction = new Runnable() { public void run() { - ++swtN ; - System.err.println("[SWT A-i shallStop "+shallStop+"]: Counter[loc "+swtN+", glob: "+incrSWTCount()+"]"); + ++swtN ; incrSWTCount(); + System.err.println("[SWT A-i shallStop "+shallStop+"]: Counter[loc "+swtN+", glob: "+getSWTCount()+"]"); } }; final Runnable newtAsyncAction = new Runnable() { public void run() { - ++newtN ; - System.err.println("[NEWT A-i shallStop "+shallStop+"]: Counter[loc "+newtN+", glob: "+incrNEWTCount()+"]"); + ++newtN ; incrNEWTCount(); + System.err.println("[NEWT A-i shallStop "+shallStop+"]: Counter[loc "+newtN+", glob: "+getNEWTCount()+"]"); } }; public void run() @@ -219,9 +220,13 @@ public class TestSWTBug643AsyncExec extends UITestCase { final GLAutoDrawable glad; if( useJOGLGLCanvas ) { - glad = GLCanvas.create(dsc.composite, 0, caps, null, null); - glad.addGLEventListener( new GearsES2() ) ; - newtDisplay = null; + final GearsES2 demo = new GearsES2(); + final GLCanvas glc = GLCanvas.create(dsc.composite, 0, caps, null, null); + final SWTNewtEventFactory swtNewtEventFactory = new SWTNewtEventFactory(); + swtNewtEventFactory.attachDispatchListener(glc, glc, demo.gearsMouse, demo.gearsKeys); + glc.addGLEventListener( demo ) ; + glad = glc; + newtDisplay = null; } else if( useNewtCanvasSWT ) { final GLWindow glWindow = GLWindow.create( caps ) ; glWindow.addGLEventListener( new GearsES2() ) ; @@ -287,8 +292,9 @@ public class TestSWTBug643AsyncExec extends UITestCase { try { final Display d = dsc.display; while( !shallStop && !d.isDisposed() ) { - if( !d.readAndDispatch() ) { - dsc.display.sleep(); + if( !d.readAndDispatch() && !shallStop ) { + // blocks on linux .. dsc.display.sleep(); + Thread.sleep(10); } } } catch (Exception e0) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java index a5d2c8012..1822d2eaf 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTJOGLGLCanvas01GLn.java @@ -50,6 +50,7 @@ import org.junit.Test; import com.jogamp.nativewindow.swt.SWTAccessor; import com.jogamp.opengl.swt.GLCanvas; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.jogl.demos.es2.MultisampleDemoES2; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.GLReadBufferUtil; @@ -58,10 +59,9 @@ import com.jogamp.opengl.util.texture.TextureIO; /** * Tests that a basic SWT app can open without crashing under different GL profiles. *

    - * Uses JOGL's new SWT GLCanvas. - *

    - *

    - * Note: To employ custom GLCapabilities, NewtCanvasSWT shall be used. + * Uses JOGL's new SWT GLCanvas, + * which allows utilizing custom GLCapability settings, + * independent from the already instantiated SWT visual. *

    *

    * Note that {@link SWTAccessor#invoke(boolean, Runnable)} is still used to comply w/ @@ -188,6 +188,14 @@ public class TestSWTJOGLGLCanvas01GLn extends UITestCase { runTestAGL( new GLCapabilities(GLProfile.getGL2ES2()), new GearsES2() ); } + @Test + public void test_MultisampleAndAlpha() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(GLProfile.getGL2ES2()); + caps.setSampleBuffers(true); + caps.setNumSamples(2); + runTestAGL( caps, new MultisampleDemoES2(true) ); + } + static int atoi(String a) { int i=0; try { -- cgit v1.2.3