diff options
Diffstat (limited to 'src/newt/classes/com/jogamp')
-rw-r--r-- | src/newt/classes/com/jogamp/newt/Display.java | 17 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/Window.java | 16 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java | 80 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/event/KeyEvent.java | 2 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/opengl/GLWindow.java | 55 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java | 508 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java | 99 |
7 files changed, 731 insertions, 46 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 7b6849a30..1e9a0e9eb 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -141,6 +141,23 @@ public abstract class Display { */ public abstract String getType(); + /** + * Sets a new {@link EDTUtil} and returns the previous one. + * <p> + * If <code>newEDTUtil</code> is <code>null</code>, + * the device's default EDTUtil is created and used. + * </p> + * <p> + * If a previous one exists and it differs from the new one, + * it's being stopped, wait-until-idle and reset to allow restart. + * </p> + * <p> + * If <code>newEDTUtil</code> is not null and equals the previous one, + * <code>null</code> is returned and no change is being made. + * </p> + */ + public abstract EDTUtil setEDTUtil(EDTUtil newEDTUtil); + public abstract EDTUtil getEDTUtil(); public abstract boolean isEDTRunning(); diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 71e86d520..e8537fec5 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -40,8 +40,20 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.WindowClosingProtocol; /** - * Specifying the public Window functionality for the - * using a Window and for shadowing one like {@link com.jogamp.newt.opengl.GLWindow}. + * Specifying NEWT's Window functionality: + * <ul> + * <li>On- and offscreen windows</li> + * <li>Keyboard and multi-pointer input</li> + * <li>Native reparenting</li> + * <li>Toggable fullscreen and decoration mode</li> + * <li>Transparency</li> + * <li>... and more</li> + * </ul> + * <p> + * One use case is {@link com.jogamp.newt.opengl.GLWindow}, which delegates + * window operation to an instance of this interface while providing OpenGL + * functionality. + * </p> */ public interface Window extends NativeWindow, WindowClosingProtocol { public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent"); diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 9af4a02ae..6f0028a77 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -42,7 +42,9 @@ import java.security.PrivilegedAction; import java.util.Set; import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.WindowClosingProtocol; import javax.swing.MenuSelectionManager; @@ -261,17 +263,35 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto private final FocusPropertyChangeListener focusPropertyChangeListener = new FocusPropertyChangeListener(); private volatile KeyboardFocusManager keyboardFocusManager = null; - /** sets a new NEWT child, provoking reparenting. */ - private NewtCanvasAWT setNEWTChild(Window child) { - if(newtChild!=child) { - newtChild = child; - if(isDisplayable()) { - // reparent right away, addNotify has been called already - final java.awt.Container cont = AWTMisc.getContainer(this); - reparentWindow( (null!=child) ? true : false, cont ); - } + /** + * Sets a new NEWT child, provoking reparenting. + * <p> + * A previously detached <code>newChild</code> will be released to top-level status + * and made invisible. + * </p> + * <p> + * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code> + * produced much cleaner visual results. + * </p> + * @return the previous attached newt child. + */ + public Window setNEWTChild(Window newChild) { + final Window prevChild = newtChild; + if(DEBUG) { + System.err.println("NewtCanvasAWT.setNEWTChild.0: win "+newtWinHandleToHexString(prevChild)+" -> "+newtWinHandleToHexString(newChild)); + } + final java.awt.Container cont = AWTMisc.getContainer(this); + // remove old one + if(null != newtChild) { + reparentWindow( false, cont ); + newtChild = null; } - return this; + // add new one, reparent only if ready + newtChild = newChild; + if( isDisplayable() && null != newChild) { + reparentWindow( true, cont ); + } + return prevChild; } /** @return the current NEWT child */ @@ -304,13 +324,13 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto awtKeyAdapter.removeFrom(this); awtKeyAdapter = null; } - newtChild.setKeyboardFocusHandler(null); if(null != keyboardFocusManager) { keyboardFocusManager.removePropertyChangeListener("focusOwner", focusPropertyChangeListener); keyboardFocusManager = null; } if( null != newtChild ) { + newtChild.setKeyboardFocusHandler(null); if(attach) { if(null == jawtWindow.getGraphicsConfiguration()) { throw new InternalError("XXX"); @@ -358,7 +378,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto // if ( isShowing() == true ) -> Container is already visible. System.err.println("NewtCanvasAWT.addNotify: "+newtChild+", "+this+", visible "+isVisible()+", showing "+isShowing()+ ", displayable "+isDisplayable()+" -> "+cont); - } + } reparentWindow(true, cont); } @@ -368,7 +388,17 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto if(DEBUG) { System.err.println("NewtCanvasAWT.removeNotify: "+newtChild+", from "+cont); } + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(newtChild, true); + if(null != ols && ols.isSurfaceLayerAttached()) { + ols.detachSurfaceLayer(); + } reparentWindow(false, cont); + + if(null != jawtWindow) { + NewtFactoryAWT.destroyNativeWindow(jawtWindow); + jawtWindow=null; + } + super.removeNotify(); } @@ -376,14 +406,19 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto if(null==newtChild) { return; // nop } + if(DEBUG) { + System.err.println("NewtCanvasAWT.reparentWindow.0: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } newtChild.setFocusAction(null); // no AWT focus traversal .. if(add) { - jawtWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); - jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); if(DEBUG) { System.err.println("NewtCanvasAWT.reparentWindow: newtChild: "+newtChild); } + if(null == jawtWindow) { + jawtWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); + jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); + } final int w; final int h; if(isPreferredSizeSet()) { @@ -407,19 +442,17 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto newtChild.setVisible(true); configureNewtChild(true); newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener - newtChild.windowRepaint(0, 0, w, h); // force this AWT Canvas to be focus-able, // since this it is completely covered by the newtChild (z-order). setFocusable(true); } else { - configureNewtChild(false); + configureNewtChild(false); newtChild.setVisible(false); newtChild.reparentWindow(null); - if(null != jawtWindow) { - NewtFactoryAWT.destroyNativeWindow(jawtWindow); - jawtWindow=null; - } + } + if(DEBUG) { + System.err.println("NewtCanvasAWT.reparentWindow.X: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); } } @@ -563,5 +596,12 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } } } + + static String newtWinHandleToHexString(Window w) { + return null != w ? toHexString(w.getWindowHandle()) : "nil"; + } + static String toHexString(long l) { + return "0x"+Long.toHexString(l); + } } diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java index 44fcea49c..4db661eeb 100644 --- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java @@ -43,7 +43,7 @@ public class KeyEvent extends InputEvent this.keyChar=keyChar; } - /** Only valid if delivered via {@link KeyListener#keyPressed(KeyEvent)} */ + /** Only valid on all platforms at {@link KeyListener#keyTyped(KeyEvent)} */ public char getKeyChar() { return keyChar; } diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index f08fbc8fa..0fc1b4e89 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -53,6 +53,7 @@ import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import jogamp.newt.WindowImpl; @@ -62,6 +63,7 @@ import jogamp.opengl.GLDrawableImpl; import com.jogamp.common.GlueGenVersion; import com.jogamp.common.util.VersionUtil; +import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Screen; import com.jogamp.newt.Window; @@ -87,13 +89,6 @@ import com.jogamp.opengl.JoglVersion; * you can inject {@link javax.media.opengl.GLRunnable} objects * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.<br> * </p> - * <p> - * NOTE: [MT-0] Methods utilizing [volatile] drawable/context are not synchronized. - In case any of the methods are called outside of a locked state - extra care should be added. Maybe we shall expose locking facilities to the user. - However, since the user shall stick to the GLEventListener model while utilizing - GLAutoDrawable implementations, she is safe due to the implicit locked state. - * </p> */ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Window, NEWTEventConsumer, FPSCounter { private final WindowImpl window; @@ -102,7 +97,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind * Constructor. Do not call this directly -- use {@link #create()} instead. */ protected GLWindow(Window window) { - super(null, null); + super(null, null, false); this.window = (WindowImpl) window; this.window.setHandleDestroyNotify(false); window.addWindowListener(new WindowAdapter() { @@ -124,6 +119,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind this.window.setLifecycleHook(new GLLifecycleHook()); } + @Override + public final Object getUpstreamWidget() { + return window; + } + /** * Creates a new GLWindow attaching a new Window referencing a * new default Screen and default Display with the given GLCapabilities. @@ -426,23 +426,23 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind @Override public synchronized void destroyActionInLock() { if(Window.DEBUG_IMPLEMENTATION) { - String msg = "GLWindow.destroy() "+Thread.currentThread()+", start"; + String msg = "GLWindow.destroy() "+WindowImpl.getThreadName()+", start"; System.err.println(msg); //Exception e1 = new Exception(msg); //e1.printStackTrace(); } - defaultDestroyOp(); + destroyImplInLock(); if(Window.DEBUG_IMPLEMENTATION) { - System.err.println("GLWindow.destroy() "+Thread.currentThread()+", fin"); + System.err.println("GLWindow.destroy() "+WindowImpl.getThreadName()+", fin"); } } @Override public synchronized void resetCounter() { if(Window.DEBUG_IMPLEMENTATION) { - System.err.println("GLWindow.resetCounter() "+Thread.currentThread()); + System.err.println("GLWindow.resetCounter() "+WindowImpl.getThreadName()); } GLWindow.this.resetFPSCounter(); } @@ -452,7 +452,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind long t0; if(Window.DEBUG_IMPLEMENTATION) { t0 = System.nanoTime(); - System.err.println("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", start"); + System.err.println("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+WindowImpl.getThreadName()+", start"); } else { t0 = 0; } @@ -479,7 +479,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind context.setContextCreationFlags(additionalCtxCreationFlags); } if(Window.DEBUG_IMPLEMENTATION) { - System.err.println("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", fin: dt "+ (System.nanoTime()-t0)/1e6 +"ms"); + System.err.println("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+WindowImpl.getThreadName()+", fin: dt "+ (System.nanoTime()-t0)/1e6 +"ms"); } } @@ -509,6 +509,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind private GLContext sharedContext = null; + @Override + protected final RecursiveLock getLock() { + return window.getLock(); + } + /** * Specifies an {@link javax.media.opengl.GLContext OpenGL context} to share with.<br> * At native creation, {@link #setVisible(boolean) setVisible(true)}, @@ -531,19 +536,18 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind return; } - window.lockWindow(); // sync: context/drawable could have been recreated/destroyed while animating + final RecursiveLock lock = window.getLock(); + lock.lock(); // sync: context/drawable could have been recreated/destroyed while animating try { - if( null == context && 0<getWidth()*getHeight() ) { - // retry drawable and context creation - setVisible(true); - } - if( null != context ) { // surface is locked/unlocked implicit by context's makeCurrent/release helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction); + } else if( 0<getWidth()*getHeight() ) { + // retry drawable and context creation, will itself issue resize -> display + setVisible(true); } } finally { - window.unlockWindow(); + lock.unlock(); } } @@ -553,7 +557,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind private GLDrawableFactory factory; @Override - public GLDrawableFactory getFactory() { + public final GLDrawableFactory getFactory() { return factory; } @@ -561,6 +565,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind public final void setRealized(boolean realized) { } + @Override + public final void swapBuffers() throws GLException { + defaultSwapBuffers(); + } + //---------------------------------------------------------------------- // NEWTEventConsumer // @@ -762,7 +771,7 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind System.err.println(GlueGenVersion.getInstance()); System.err.println(JoglVersion.getInstance()); - System.err.println(JoglVersion.getDefaultOpenGLInfo(null, true).toString()); + System.err.println(JoglVersion.getDefaultOpenGLInfo(null, null, true).toString()); final GLProfile glp = GLProfile.getDefault(); final GLCapabilitiesImmutable caps = new GLCapabilities( glp ); diff --git a/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java new file mode 100644 index 000000000..f45b864fa --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/swt/NewtCanvasSWT.java @@ -0,0 +1,508 @@ +/** + * 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.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.nativewindow.util.Point; + +import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.newt.Debug; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; + +import com.jogamp.nativewindow.swt.SWTAccessor; +import com.jogamp.newt.Display; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.util.EDTUtil; + +public class NewtCanvasSWT extends Canvas implements WindowClosingProtocol { + private static final boolean DEBUG = Debug.debug("Window"); + private static final boolean isOSX = NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false); + + /** SWT EDTUtil associated w/ parent's SWT Display */ + private final EDTUtil swtEDTUtil; + + private final AbstractGraphicsScreen screen; + + private WindowClosingMode newtChildCloseOp = WindowClosingMode.DISPOSE_ON_CLOSE; + private volatile Rectangle clientArea; + + private volatile SWTNativeWindow nativeWindow; + private volatile Window newtChild = null; + + /** + * Creates an instance using {@link #NewtCanvasSWT(Composite, int, Window)} + * on the SWT thread. + * + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an SWT conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * + * @param parent the SWT composite + * @param style additional styles to SWT#NO_BACKGROUND + * @param child optional preassigned {@link #Window}, maybe null + * @return a new instance + */ + public static NewtCanvasSWT create(final Composite parent, final int style, final Window child) { + final NewtCanvasSWT[] res = new NewtCanvasSWT[] { null }; + parent.getDisplay().syncExec( new Runnable() { + public void run() { + res[0] = new NewtCanvasSWT( parent, style, child); + } + }); + return res[0]; + } + + /** + * Instantiates a NewtCanvas with a NEWT child. + * + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an SWT conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * + * @param parent the SWT composite + * @param style additional styles to SWT#NO_BACKGROUND + * @param child optional preassigned {@link #Window}, maybe null + */ + public NewtCanvasSWT(final Composite parent, final int style, Window child) { + super(parent, style | SWT.NO_BACKGROUND); + + swtEDTUtil = new SWTEDTUtil(parent.getDisplay()); + + SWTAccessor.setRealized(this, true); + + clientArea = getClientArea(); + + final AbstractGraphicsDevice device = SWTAccessor.getDevice(this); + screen = SWTAccessor.getScreen(device, 0); + 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() { + @Override + public void paintControl(final PaintEvent arg0) { + if( null != nativeWindow || validateNative() ) { + if( null !=newtChild ) { + newtChild.windowRepaint(0, 0, clientArea.width, clientArea.height); + } + } + } + }); + + addControlListener(new ControlAdapter() { + @Override + public void controlResized(final ControlEvent arg0) { + updateSizeCheck(); + } + }); + } + + /** assumes nativeWindow == null ! */ + protected final boolean validateNative() { + if( isDisposed() ) { + return false; + } + updateSizeCheck(); + final Rectangle nClientArea = clientArea; + if(0 == nClientArea.width * nClientArea.height) { + return false; + } + + /* Native handle for the control, used to associate with GLContext */ + final long nativeWindowHandle = SWTAccessor.getWindowHandle(this); + final int visualID = SWTAccessor.getNativeVisualID(screen.getDevice(), nativeWindowHandle); + final boolean visualIDValid = NativeWindowFactory.isNativeVisualIDValidForProcessing(visualID); + if(DEBUG) { + System.err.println("NewtCanvasSWT.validateNative() windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", valid "+visualIDValid); + } + if( visualIDValid ) { + /* 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 no closing operation will be a NOP. */ + final CapabilitiesImmutable caps = new Capabilities(); + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(screen.getDevice(), caps); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration( caps, caps, null, screen, visualID ); + if(DEBUG) { + System.err.println("NewtCanvasSWT.validateNative() factory: "+factory+", windowHandle 0x"+Long.toHexString(nativeWindowHandle)+", visualID 0x"+Integer.toHexString(visualID)+", chosen config: "+config); + // Thread.dumpStack(); + } + if (null == config) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + nativeWindow = new SWTNativeWindow(config, nativeWindowHandle); + reparentWindow( true ); + } + + return null != nativeWindow; + } + + protected final void updateSizeCheck() { + final Rectangle oClientArea = clientArea; + final Rectangle nClientArea = getClientArea(); + if ( nClientArea != null && + ( nClientArea.width != oClientArea.width || nClientArea.height != oClientArea.height ) + ) { + clientArea = nClientArea; // write back new value + if( null != newtChild ) { + newtChild.setSize(clientArea.width, clientArea.height); + } + } + } + + @Override + public void update() { + // don't paint background etc .. nop avoids flickering + } + + /** + * Destroys this resource: + * <ul> + * <li> Make the NEWT Child invisible </li> + * <li> Disconnects the NEWT Child from this Canvas NativeWindow, reparent to NULL </li> + * <li> Issues <code>destroy()</code> on the NEWT Child</li> + * <li> Remove reference to the NEWT Child</li> + * </ul> + * @see Window#destroy() + */ + @Override + public void dispose() { + if( null != newtChild ) { + if(DEBUG) { + System.err.println("NewtCanvasSWT.dispose.0: EDTUtil cur "+newtChild.getScreen().getDisplay().getEDTUtil()+ + ",\n\t"+newtChild); + } + configureNewtChild(false); + newtChild.setVisible(false); + newtChild.reparentWindow(null); + newtChild.destroy(); + newtChild = null; + } + nativeWindow = null; + super.dispose(); + } + + /** @return this SWT Canvas NativeWindow representation, may be null in case it has not been realized. */ + public NativeWindow getNativeWindow() { return nativeWindow; } + + public WindowClosingMode getDefaultCloseOperation() { + return newtChildCloseOp; // FIXME + } + + public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) { + return newtChildCloseOp = op; // FIXME + } + + + boolean isParent() { + return null!=newtChild ; + } + + boolean isFullscreen() { + return null != newtChild && newtChild.isFullscreen(); + } + + /** + * Sets a new NEWT child, provoking reparenting. + * <p> + * A previously detached <code>newChild</code> will be released to top-level status + * and made invisible. + * </p> + * <p> + * Note: When switching NEWT child's, detaching the previous first via <code>setNEWTChild(null)</code> + * produced much cleaner visual results. + * </p> + * <p> + * Note: The NEWT child {@link Display}'s {@link EDTUtil} is being set to an SWT conform implementation + * via {@link Display#setEDTUtil(EDTUtil)}. + * </p> + * @return the previous attached newt child. + */ + public Window setNEWTChild(final Window newChild) { + final Window prevChild = newtChild; + if(DEBUG) { + System.err.println("NewtCanvasSWT.setNEWTChild.0: win "+newtWinHandleToHexString(prevChild)+" -> "+newtWinHandleToHexString(newChild)); + } + // remove old one + if(null != newtChild) { + reparentWindow( false ); + newtChild = null; + } + // add new one, reparent only if ready + newtChild = newChild; + if(null != nativeWindow && null != newChild) { + reparentWindow( true ); + } + return prevChild; + } + + /** @return the current NEWT child */ + public Window getNEWTChild() { + return newtChild; + } + + @Override + public boolean setParent(Composite parent) { + return super.setParent(parent); + } + + /* package */ void configureNewtChild(boolean attach) { + + if( null != newtChild ) { + newtChild.setKeyboardFocusHandler(null); + if(attach) { + newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE); + } else { + newtChild.setFocusAction(null); + newtChild.setDefaultCloseOperation(newtChildCloseOp); + } + } + } + + void reparentWindow(boolean add) { + if( null == newtChild ) { + return; // nop + } + if(DEBUG) { + System.err.println("NewtCanvasSWT.reparentWindow.0: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + + newtChild.setFocusAction(null); // no AWT focus traversal .. + if(add) { + updateSizeCheck(); + final int w = clientArea.width; + final int h = clientArea.height; + + newtChild.getScreen().getDisplay().setEDTUtil(swtEDTUtil); + + newtChild.setSize(w, h); + newtChild.reparentWindow(nativeWindow); + newtChild.setVisible(true); + configureNewtChild(true); + newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener + + // force this SWT Canvas to be focus-able, + // since this it is completely covered by the newtChild (z-order). + setEnabled(true); + } else { + configureNewtChild(false); + newtChild.setVisible(false); + newtChild.reparentWindow(null); + } + if(DEBUG) { + System.err.println("NewtCanvasSWT.reparentWindow.X: add="+add+", win "+newtWinHandleToHexString(newtChild)+", EDTUtil: cur "+newtChild.getScreen().getDisplay().getEDTUtil()); + } + } + + private final void requestFocusNEWTChild() { + if( null != newtChild ) { + newtChild.setFocusAction(null); + newtChild.requestFocus(); + } + } + + @Override + public boolean forceFocus() { + final boolean res = NewtCanvasSWT.super.forceFocus(); + requestFocusNEWTChild(); + return res; + } + + private class SWTNativeWindow implements NativeWindow { + private final AbstractGraphicsConfiguration config; + private final long nativeWindowHandle; + private final InsetsImmutable insets; // only required to allow proper client position calculation on OSX + + public SWTNativeWindow(AbstractGraphicsConfiguration config, long nativeWindowHandle) { + this.config = config; + this.nativeWindowHandle = nativeWindowHandle; + if(isOSX) { + this.insets = OSXUtil.GetInsets(nativeWindowHandle); + } else { + this.insets = new Insets(0, 0, 0, 0); + } + } + + @Override + public int lockSurface() throws NativeWindowException, RuntimeException { + return NativeSurface.LOCK_SUCCESS; + } + + @Override + public void unlockSurface() { } + + @Override + public boolean isSurfaceLockedByOtherThread() { + return false; + } + + @Override + public Thread getSurfaceLockOwner() { + return null; + } + + @Override + public boolean surfaceSwap() { + return false; + } + + @Override + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { } + + @Override + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + } + + @Override + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { } + + @Override + public long getSurfaceHandle() { + return 0; + } + + @Override + public int getWidth() { + return clientArea.width; + } + + @Override + public int getHeight() { + return clientArea.height; + } + + @Override + public AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config; + } + + @Override + public long getDisplayHandle() { + return config.getScreen().getDevice().getHandle(); + } + + @Override + public int getScreenIndex() { + return config.getScreen().getIndex(); + } + + @Override + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { } + + @Override + public void destroy() { } + + @Override + public NativeWindow getParent() { + return null; + } + + @Override + public long getWindowHandle() { + return nativeWindowHandle; + } + + @Override + public InsetsImmutable getInsets() { + return insets; + } + + @Override + public int getX() { + return 0; + } + + @Override + public int getY() { + return 0; + } + + @Override + public Point getLocationOnScreen(Point point) { + if( isOSX ) { + final Point los = OSXUtil.GetLocationOnScreen(nativeWindowHandle, false, 0, 0); + // top-level position -> client window position + los.setX(los.getX() + insets.getLeftWidth()); + los.setY(los.getY() + insets.getTopHeight()); + if(null!=point) { + return point.translate(los); + } else { + return los; + } + } else { + // client position on 'normal' windowing systems is 0/0 + if(null == point) { + point = new Point(0, 0); + } + return point; + } + } + + @Override + public boolean hasFocus() { + return isFocusControl(); + } + }; + + static String newtWinHandleToHexString(Window w) { + return null != w ? toHexString(w.getWindowHandle()) : "nil"; + } + static String toHexString(long l) { + return "0x"+Long.toHexString(l); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java new file mode 100644 index 000000000..3538caad2 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/swt/SWTEDTUtil.java @@ -0,0 +1,99 @@ +/** + * 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 org.eclipse.swt.widgets.Display; + +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 { + private final Display swtDisplay; + + public SWTEDTUtil(Display swtDisplay) { + this.swtDisplay = swtDisplay; + } + + public final Display getDisplay() { + return swtDisplay; + } + + @Override + public long getPollPeriod() { + return 0; + } + + @Override + public void setPollPeriod(long ms) { + } + + @Override + public void reset() { + } + + @Override + public void start() { + } + + @Override + public boolean isCurrentThreadEDT() { + return swtDisplay.getThread() == Thread.currentThread(); + } + + @Override + public boolean isRunning() { + return true; + } + + @Override + public void invokeStop(Runnable finalTask) { + swtDisplay.syncExec(finalTask); + } + + @Override + public void invoke(boolean wait, Runnable task) { + if(wait) { + swtDisplay.syncExec(task); + } else { + swtDisplay.asyncExec(task); + } + } + + @Override + public void waitUntilIdle() { + // all sync .. + } + + @Override + public void waitUntilStopped() { + // all sync .. + } +} |