diff options
Diffstat (limited to 'src/newt/classes/com/jogamp')
33 files changed, 3406 insertions, 2744 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 5e3e32964..b09f63962 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -1,85 +1,95 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution 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. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * +/** + * Copyright 2010 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; -import javax.media.nativewindow.*; -import com.jogamp.nativewindow.impl.RecursiveToolkitLock; -import com.jogamp.newt.event.*; -import com.jogamp.newt.impl.event.*; -import com.jogamp.newt.impl.Debug; import com.jogamp.newt.util.EDTUtil; -import com.jogamp.newt.util.MainThread; -import com.jogamp.newt.util.DefaultEDTUtil; +import com.jogamp.newt.impl.Debug; +import com.jogamp.newt.impl.DisplayImpl; + import java.util.*; +import javax.media.nativewindow.AbstractGraphicsDevice; + public abstract class Display { public static final boolean DEBUG = Debug.debug("Display"); - public static final boolean DEBUG_TEST_EDT_MAINTHREAD = Debug.isPropertyDefined("newt.test.EDTMainThread", true); // JAU EDT Test .. - private static Class getDisplayClass(String type) - throws ClassNotFoundException - { - Class displayClass = NewtFactory.getCustomClass(type, "Display"); - if(null==displayClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDDisplay"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.windows.WindowsDisplay"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.macosx.MacDisplay"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.x11.X11Display"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.awt.AWTDisplay"); - } else { - throw new RuntimeException("Unknown display type \"" + type + "\""); - } - } - return displayClass; - } + /** + * @return true if the native display handle is valid and ready to operate, + * otherwise false. + * + * @see #destroy() + */ + public abstract boolean isNativeValid(); + + /** + * @return number of references by Screen + */ + public abstract int getReferenceCount(); + + public abstract void destroy(); + + public abstract boolean getDestroyWhenUnused(); + + /** + * + * @param v + */ + public abstract void setDestroyWhenUnused(boolean v); + public abstract AbstractGraphicsDevice getGraphicsDevice(); + + public abstract String getFQName(); + + public abstract long getHandle(); + + public abstract int getId(); + + public abstract String getName(); + + public abstract String getType(); + + public abstract EDTUtil getEDTUtil(); + + public abstract boolean isEDTRunning(); + + public abstract void dispatchMessages(); + // Global Displays - private static ArrayList displayList = new ArrayList(); - private static int displaysActive = 0; - private static int serialno = 1; + protected static ArrayList displayList = new ArrayList(); + protected static int displaysActive = 0; public static void dumpDisplayList(String prefix) { synchronized(displayList) { Iterator i = displayList.iterator(); System.err.println(prefix+" DisplayList[] entries: "+displayList.size()+" - "+getThreadName()); for(int j=0; i.hasNext(); j++) { - Display d = (Display) i.next(); + DisplayImpl d = (DisplayImpl) i.next(); System.err.println(" ["+j+"] : "+d); } } @@ -100,219 +110,6 @@ public abstract class Display { } } - /** Make sure to reuse a Display with the same name */ - protected static Display create(String type, String name, final long handle) { - try { - Class displayClass = getDisplayClass(type); - Display display = (Display) displayClass.newInstance(); - name = display.validateDisplayName(name, handle); - display.name = name; - display.type=type; - display.destroyWhenUnused=false; - synchronized(displayList) { - display.id = serialno++; - display.fqname = getFQName(display.id, display.type, display.name); - displayList.add(display); - } - display.createEDTUtil(); - if(DEBUG) { - System.err.println("Display.create() NEW: "+display+" "+getThreadName()); - } - return display; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected synchronized final void createNative() { - if(null==aDevice) { - if(DEBUG) { - System.err.println("Display.createNative() START ("+getThreadName()+", "+this+")"); - } - final Display f_dpy = this; - runOnEDTIfAvail(true, new Runnable() { - public void run() { - f_dpy.createNativeImpl(); - }}); - if(null==aDevice) { - throw new RuntimeException("Display.createNative() failed to instanciate an AbstractGraphicsDevice"); - } - if(DEBUG) { - System.err.println("Display.createNative() END ("+getThreadName()+", "+this+")"); - } - synchronized(displayList) { - displaysActive++; - } - } - } - - protected boolean shallRunOnEDT() { - return true; - } - - protected void createEDTUtil() { - if(NewtFactory.useEDT()) { - if ( ! DEBUG_TEST_EDT_MAINTHREAD ) { - Thread current = Thread.currentThread(); - edtUtil = new DefaultEDTUtil(current.getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable); - } else { - // Begin JAU EDT Test .. - MainThread.addPumpMessage(this, dispatchMessagesRunnable); - edtUtil = MainThread.getSingleton(); - // End JAU EDT Test .. - } - if(DEBUG) { - System.err.println("Display.createNative("+getFQName()+") Create EDTUtil: "+edtUtil.getClass().getName()); - } - } - } - - public final EDTUtil getEDTUtil() { - return edtUtil; - } - - public void runOnEDTIfAvail(boolean wait, final Runnable task) { - if( shallRunOnEDT() && null!=edtUtil ) { - edtUtil.invoke(wait, task); - } else { - task.run(); - } - } - - public synchronized final void destroy() { - if ( null != aDevice ) { - if(DEBUG) { - dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); - } - synchronized(displayList) { - displayList.remove(this); - displaysActive--; - } - if(DEBUG) { - System.err.println("Display.destroy(): "+this+" "+getThreadName()); - } - final Display f_dpy = this; - final EDTUtil f_edtUtil = edtUtil; - runOnEDTIfAvail(true, new Runnable() { - public void run() { - f_dpy.closeNativeImpl(); - if(null!=f_edtUtil) { - f_edtUtil.stop(); - } - } - } ); - if(null!=edtUtil) { - if ( DEBUG_TEST_EDT_MAINTHREAD ) { - MainThread.removePumpMessage(this); // JAU EDT Test .. - } - edtUtil.waitUntilStopped(); - edtUtil.reset(); - } - aDevice = null; - if(DEBUG) { - dumpDisplayList("Display.destroy("+getFQName()+") END"); - } - } - } - - protected synchronized final int addReference() { - if(DEBUG) { - System.err.println("Display.addReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount+1)); - } - if ( 0 == refCount ) { - createNative(); - } - if(null == aDevice) { - throw new RuntimeException("Display.addReference() (refCount "+refCount+") null AbstractGraphicsDevice"); - } - return ++refCount; - } - - - protected synchronized final int removeReference() { - if(DEBUG) { - System.err.println("Display.removeReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount-1)); - } - refCount--; - if(0==refCount && destroyWhenUnused) { - destroy(); - } - return refCount; - } - - /** - * @return number of references by Screen - */ - public synchronized final int getReferenceCount() { - return refCount; - } - - public final boolean getDestroyWhenUnused() { return destroyWhenUnused; } - public final void setDestroyWhenUnused(boolean v) { destroyWhenUnused=v; } - - protected abstract void createNativeImpl(); - protected abstract void closeNativeImpl(); - - public final int getId() { - return id; - } - - public final String getType() { - return type; - } - - public final String getName() { - return name; - } - - public final String getFQName() { - return fqname; - } - - public static final String nilString = "nil" ; - - public String validateDisplayName(String name, long handle) { - if(null==name && 0!=handle) { - name="wrapping-"+toHexString(handle); - } - return ( null == name ) ? nilString : name ; - } - - public static final String getFQName(int id, String type, String name) { - if(null==type) type=nilString; - if(null==name) name=nilString; - StringBuffer sb = new StringBuffer(); - sb.append(type); - sb.append("_"); - sb.append(name); - sb.append("-"); - sb.append(id); - return sb.toString(); - } - - public final long getHandle() { - if(null!=aDevice) { - return aDevice.getHandle(); - } - return 0; - } - - public final AbstractGraphicsDevice getGraphicsDevice() { - return aDevice; - } - - public final boolean isNativeValid() { - return null != aDevice; - } - - public synchronized void pumpMessages() { - dispatchMessages(); - } - - public String toString() { - return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", "+aDevice+"]"; - } - public static String getThreadName() { return Thread.currentThread().getName(); } @@ -325,93 +122,7 @@ public abstract class Display { return "0x" + Long.toHexString(hex); } - - protected abstract void dispatchMessagesNative(); - - private Object eventsLock = new Object(); - private LinkedList/*<NEWTEvent>*/ events = new LinkedList(); - - class DispatchMessagesRunnable implements Runnable { - public void run() { - Display.this.dispatchMessages(); - } - } - DispatchMessagesRunnable dispatchMessagesRunnable = new DispatchMessagesRunnable(); - - public void dispatchMessages() { - if(0==refCount) return; // no screens - if(null==getGraphicsDevice()) return; // no native device - - LinkedList/*<NEWTEvent>*/ _events = null; - - if(!events.isEmpty()) { - // swap events list to free ASAP - synchronized(eventsLock) { - if(!events.isEmpty()) { - _events = events; - events = new LinkedList(); - } - eventsLock.notifyAll(); - } - if( null != _events ) { - for (Iterator iter = _events.iterator(); iter.hasNext(); ) { - NEWTEventTask eventTask = (NEWTEventTask) iter.next(); - NEWTEvent event = eventTask.get(); - Object source = event.getSource(); - if(source instanceof NEWTEventConsumer) { - NEWTEventConsumer consumer = (NEWTEventConsumer) source ; - if(!consumer.consumeEvent(event)) { - enqueueEvent(false, event); - } - } else { - throw new RuntimeException("Event source not NEWT: "+source.getClass().getName()+", "+source); - } - eventTask.notifyIssuer(); - } - } - } - - // lock(); - try { - dispatchMessagesNative(); - } finally { - // unlock(); - } - } - - public void enqueueEvent(boolean wait, NEWTEvent e) { - Object lock = new Object(); - NEWTEventTask eTask = new NEWTEventTask(e, wait?lock:null); - synchronized(lock) { - synchronized(eventsLock) { - events.addLast(eTask); - eventsLock.notifyAll(); - } - if( wait ) { - try { - lock.wait(); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - } - } - - public void lock() { - aDevice.lock(); + public static int hashCode(Object o) { + return ( null != o ) ? o.hashCode() : 0; } - - public void unlock() { - aDevice.unlock(); - } - - protected EDTUtil edtUtil = null; - protected int id; - protected String name; - protected String type; - protected String fqname; - protected int refCount; // number of Display references by Screen - protected boolean destroyWhenUnused; - protected AbstractGraphicsDevice aDevice; } - diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index 7c610c1b8..5f969777a 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -40,19 +41,22 @@ import java.util.Iterator; import com.jogamp.common.jvm.JVMUtil; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.impl.DisplayImpl; +import com.jogamp.newt.impl.ScreenImpl; +import com.jogamp.newt.impl.WindowImpl; import com.jogamp.newt.impl.Debug; -public abstract class NewtFactory { +public class NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); // Work-around for initialization order problems on Mac OS X // between native Newt and (apparently) Fmod static { JVMUtil.initSingleton(); - Window.init(NativeWindowFactory.getNativeWindowType(true)); + WindowImpl.init(NativeWindowFactory.getNativeWindowType(true)); } - static Class getCustomClass(String packageName, String classBaseName) { + public static Class getCustomClass(String packageName, String classBaseName) { Class clazz = null; if(packageName!=null || classBaseName!=null) { String clazzName = packageName + "." + classBaseName ; @@ -81,42 +85,43 @@ public abstract class NewtFactory { * Create a Display entity, incl native creation */ public static Display createDisplay(String name) { - return Display.create(NativeWindowFactory.getNativeWindowType(true), name, 0); + return DisplayImpl.create(NativeWindowFactory.getNativeWindowType(true), name, 0); } /** * Create a Display entity using the given implementation type, incl native creation */ public static Display createDisplay(String type, String name) { - return Display.create(type, name, 0); + return DisplayImpl.create(type, name, 0); } /** * Create a Screen entity, incl native creation */ public static Screen createScreen(Display display, int index) { - return Screen.create(NativeWindowFactory.getNativeWindowType(true), display, index); + return ScreenImpl.create(NativeWindowFactory.getNativeWindowType(true), display, index); } /** * Create a Screen entity using the given implementation type, incl native creation */ public static Screen createScreen(String type, Display display, int index) { - return Screen.create(type, display, index); + return ScreenImpl.create(type, display, index); } /** - * Create a top level Window entity, incl native creation + * Create a top level Window entity, incl native creation. + * The Display/Screen is created and owned, ie destructed atomatic. */ - public static Window createWindow(Screen screen, Capabilities caps) { - return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps, false); + public static Window createWindow(Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), caps); } /** * Create a top level Window entity, incl native creation */ - public static Window createWindow(Screen screen, Capabilities caps, boolean undecorated) { - return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps, undecorated); + public static Window createWindow(Screen screen, Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps); } /** @@ -131,17 +136,13 @@ public abstract class NewtFactory { * The parents visibility is passed to the new Window<br></p> * <p> * In case <code>parentWindowObject</code> is a different {@link javax.media.nativewindow.NativeWindow} implementation,<br> - * you have to handle all events appropriatly.<br></p> + * you have to handle all events appropriate.<br></p> * <p> * * @param parentWindowObject either a NativeWindow instance - * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(NativeWindow nParentWindow, Capabilities caps, boolean undecorated) { + public static Window createWindow(NativeWindow nParentWindow, Capabilities caps) { final String type = NativeWindowFactory.getNativeWindowType(true); - if(null==nParentWindow) { - return createWindowImpl(type, caps, undecorated); - } Screen screen = null; Window parentWindow = null; @@ -164,33 +165,33 @@ public abstract class NewtFactory { } screen.setDestroyWhenUnused(true); } - final Window win = createWindowImpl(type, nParentWindow, screen, caps, undecorated); + final Window win = createWindowImpl(type, nParentWindow, screen, caps); win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); if ( null != parentWindow ) { - parentWindow.getInnerWindow().addChild(win); + parentWindow.addChild(win); win.setVisible(parentWindow.isVisible()); } return win; } - protected static Window createWindowImpl(String type, NativeWindow parentNativeWindow, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, parentNativeWindow, 0, screen, caps, undecorated); + protected static Window createWindowImpl(String type, NativeWindow parentNativeWindow, Screen screen, Capabilities caps) { + return WindowImpl.create(type, parentNativeWindow, 0, screen, caps); } - protected static Window createWindowImpl(String type, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, null, parentWindowHandle, screen, caps, undecorated); + protected static Window createWindowImpl(String type, long parentWindowHandle, Screen screen, Capabilities caps) { + return WindowImpl.create(type, null, parentWindowHandle, screen, caps); } - protected static Window createWindowImpl(String type, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, null, 0, screen, caps, undecorated); + protected static Window createWindowImpl(String type, Screen screen, Capabilities caps) { + return WindowImpl.create(type, null, 0, screen, caps); } - protected static Window createWindowImpl(String type, Capabilities caps, boolean undecorated) { + protected static Window createWindowImpl(String type, Capabilities caps) { Display display = NewtFactory.createDisplay(type, null); // local display Screen screen = NewtFactory.createScreen(type, display, 0); // screen 0 screen.setDestroyWhenUnused(true); - return Window.create(type, null, 0, screen, caps, undecorated); + return WindowImpl.create(type, null, 0, screen, caps); } /** @@ -199,19 +200,19 @@ public abstract class NewtFactory { * @param parentWindowObject the native parent window handle * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), parentWindowHandle, screen, caps, undecorated); + public static Window createWindow(long parentWindowHandle, Screen screen, Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), parentWindowHandle, screen, caps); } /** - * Ability to try a Window type with a construnctor argument, if supported ..<p> + * Ability to try a Window type with a constructor argument, if supported ..<p> * Currently only valid is <code> AWTWindow(Frame frame) </code>, * to support an external created AWT Frame, ie the browsers embedded frame. * * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(NativeWindowFactory.getNativeWindowType(true), cstrArguments, screen, caps, undecorated); + public static Window createWindow(Object[] cstrArguments, Screen screen, Capabilities caps) { + return WindowImpl.create(NativeWindowFactory.getNativeWindowType(true), cstrArguments, screen, caps); } /** @@ -219,19 +220,19 @@ public abstract class NewtFactory { * * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(String type, Screen screen, Capabilities caps, boolean undecorated) { - return createWindowImpl(type, null, screen, caps, undecorated); + public static Window createWindow(String type, Screen screen, Capabilities caps) { + return createWindowImpl(type, null, screen, caps); } - public static Window createWindow(String type, Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, cstrArguments, screen, caps, undecorated); + public static Window createWindow(String type, Object[] cstrArguments, Screen screen, Capabilities caps) { + return WindowImpl.create(type, cstrArguments, screen, caps); } /** * Instantiate a Display entity using the native handle. */ public static Display createDisplay(String type, long handle) { - return Display.create(type, null, handle); + return DisplayImpl.create(type, null, handle); } private static final boolean instanceOf(Object obj, String clazzName) { @@ -251,7 +252,7 @@ public abstract class NewtFactory { AbstractGraphicsScreen parentScreen = (AbstractGraphicsScreen) parentConfig.getScreen(); AbstractGraphicsDevice parentDevice = (AbstractGraphicsDevice) parentScreen.getDevice(); - Display childDisplay = childScreen.getDisplay(); + DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay(); String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle()); String childDisplayName = childDisplay.getName(); if( ! parentDisplayName.equals( childDisplayName ) ) { @@ -276,7 +277,7 @@ public abstract class NewtFactory { if(null != childScreen) { // check if child Display/Screen is compatible already - Display childDisplay = childScreen.getDisplay(); + DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay(); String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle()); String childDisplayName = childDisplay.getName(); boolean displayEqual = parentDisplayName.equals( childDisplayName ); diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index d25da86d8..f1b4254d8 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -1,202 +1,70 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution 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. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * +/** + * Copyright 2010 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; -import com.jogamp.newt.impl.*; - -import javax.media.nativewindow.*; -import java.security.*; - -public abstract class Screen { +import com.jogamp.newt.impl.Debug; +import javax.media.nativewindow.AbstractGraphicsScreen; +public interface Screen { public static final boolean DEBUG = Debug.debug("Display"); - private static Class getScreenClass(String type) - throws ClassNotFoundException - { - Class screenClass = NewtFactory.getCustomClass(type, "Screen"); - if(null==screenClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen"); - } else { - throw new RuntimeException("Unknown window type \"" + type + "\""); - } - } - return screenClass; - } - - protected static Screen create(String type, Display display, final int idx) { - try { - if(usrWidth<0 || usrHeight<0) { - usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); - usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); - if(usrWidth>0 || usrHeight>0) { - System.err.println("User screen size "+usrWidth+"x"+usrHeight); - } - } - Class screenClass = getScreenClass(type); - Screen screen = (Screen) screenClass.newInstance(); - screen.display = display; - screen.idx = idx; - return screen; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected synchronized final void createNative() { - if(null == aScreen) { - if(DEBUG) { - System.err.println("Screen.createNative() START ("+Display.getThreadName()+", "+this+")"); - } - display.addReference(); - createNativeImpl(); - if(null == aScreen) { - throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen"); - } - if(DEBUG) { - System.err.println("Screen.createNative() END ("+Display.getThreadName()+", "+this+")"); - } - } - } - - public synchronized final void destroy() { - if ( null != aScreen ) { - closeNativeImpl(); - display.removeReference(); - aScreen = null; - } - } - - protected synchronized final int addReference() { - if(DEBUG) { - System.err.println("Screen.addReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount+1)); - } - if ( 0 == refCount ) { - createNative(); - } - if(null == aScreen) { - throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen"); - } - return ++refCount; - } + boolean isNativeValid(); - protected synchronized final int removeReference() { - if(DEBUG) { - System.err.println("Screen.removeReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount-1)); - } - refCount--; - if(0==refCount && getDestroyWhenUnused()) { - destroy(); - } - return refCount; - } - - /** + /** + * * @return number of references by Window */ - public synchronized final int getReferenceCount() { - return refCount; - } - - public final boolean getDestroyWhenUnused() { - return display.getDestroyWhenUnused(); - } - public final void setDestroyWhenUnused(boolean v) { - display.setDestroyWhenUnused(v); - } + int getReferenceCount(); - protected abstract void createNativeImpl(); - protected abstract void closeNativeImpl(); + void destroy(); - protected void setScreenSize(int w, int h) { - System.err.println("Detected screen size "+w+"x"+h); - width=w; height=h; - } + boolean getDestroyWhenUnused(); - public final Display getDisplay() { - return display; - } + void setDestroyWhenUnused(boolean v); - public final int getIndex() { - return idx; - } + AbstractGraphicsScreen getGraphicsScreen(); - public final AbstractGraphicsScreen getGraphicsScreen() { - return aScreen; - } - - public final boolean isNativeValid() { - return null != aScreen; - } + int getIndex(); /** * The actual implementation shall return the detected display value, * if not we return 800. * This can be overwritten with the user property 'newt.ws.swidth', */ - public final int getWidth() { - return (usrWidth>0) ? usrWidth : (width>0) ? width : 480; - } + int getWidth(); /** * The actual implementation shall return the detected display value, * if not we return 480. * This can be overwritten with the user property 'newt.ws.sheight', */ - public final int getHeight() { - return (usrHeight>0) ? usrHeight : (height>0) ? height : 480; - } - - public String toString() { - return "NEWT-Screen[idx "+idx+", refCount "+refCount+", "+aScreen+", "+display+"]"; - } + int getHeight(); - protected Display display; - protected int idx; - protected AbstractGraphicsScreen aScreen; - protected int refCount; // number of Screen references by Window - protected int width=-1, height=-1; // detected values: set using setScreenSize - protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight - private static AccessControlContext localACC = AccessController.getContext(); + Display getDisplay(); } - diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 67374cc00..ef3e5e69c 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -1,884 +1,118 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution 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. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * +/** + * Copyright 2010 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; -import com.jogamp.newt.event.*; -import com.jogamp.newt.util.*; +import com.jogamp.newt.util.Insets; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.NEWTEventConsumer; import com.jogamp.newt.impl.Debug; +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.SurfaceUpdatedListener; -import com.jogamp.common.util.*; -import javax.media.nativewindow.*; -import com.jogamp.nativewindow.util.Rectangle; -import com.jogamp.nativewindow.impl.RecursiveToolkitLock; - -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; -import java.lang.reflect.Method; - -public abstract class Window implements NativeWindow, NEWTEventConsumer -{ +/** + * Specifying the public Window functionality for the + * using a Window and for shadowing one like {@link com.jogamp.newt.opengl.GLWindow}. + */ +public interface Window extends NativeWindow { public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent"); public static final boolean DEBUG_KEY_EVENT = Debug.debug("Window.KeyEvent"); public static final boolean DEBUG_WINDOW_EVENT = Debug.debug("Window.WindowEvent"); public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); - public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.reparent.incompatible", true); - - // Workaround for initialization order problems on Mac OS X - // between native Newt and (apparently) Fmod -- if Fmod is - // initialized first then the connection to the window server - // breaks, leading to errors from deep within the AppKit - static void init(String type) { - if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - try { - getWindowClass(type); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private static Class getWindowClass(String type) - throws ClassNotFoundException - { - Class windowClass = NewtFactory.getCustomClass(type, "Window"); - if(null==windowClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDWindow"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.windows.WindowsWindow"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.macosx.MacWindow"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.x11.X11Window"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.awt.AWTWindow"); - } else { - throw new NativeWindowException("Unknown window type \"" + type + "\""); - } - } - return windowClass; - } - - protected static Window create(String type, NativeWindow parentNativeWindow, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - try { - Class windowClass; - if(caps.isOnscreen()) { - windowClass = getWindowClass(type); - } else { - windowClass = OffscreenWindow.class; - } - Window window = (Window) windowClass.newInstance(); - window.invalidate(true); - window.parentNativeWindow = parentNativeWindow; - window.parentWindowHandle = parentWindowHandle; - window.screen = screen; - window.caps = (Capabilities)caps.clone(); - window.setUndecorated(undecorated||0!=parentWindowHandle); - return window; - } catch (Throwable t) { - t.printStackTrace(); - throw new NativeWindowException(t); - } - } - - protected static Window create(String type, Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { - try { - Class windowClass = getWindowClass(type); - Class[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass); - if(null==cstrArgumentTypes) { - throw new NativeWindowException("WindowClass "+windowClass+" doesn't support custom arguments in constructor"); - } - int argsChecked = verifyConstructorArgumentTypes(cstrArgumentTypes, cstrArguments); - if ( argsChecked < cstrArguments.length ) { - throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments)); - } - Window window = (Window) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; - window.invalidate(true); - window.screen = screen; - window.caps = (Capabilities)caps.clone(); - window.setUndecorated(undecorated); - return window; - } catch (Throwable t) { - throw new NativeWindowException(t); - } - } - - protected Screen screen; - protected boolean screenReferenced = false; - - protected NativeWindow parentNativeWindow; - protected long parentWindowHandle; - - protected Capabilities caps; - protected AbstractGraphicsConfiguration config; - protected long windowHandle; - protected boolean fullscreen, visible; - protected int width, height, x, y; - - // non fullscreen dimensions .. - protected int nfs_width, nfs_height, nfs_x, nfs_y; - - protected String title = "Newt Window"; - protected boolean undecorated = false; - - private final boolean createNative() { - if( null==screen || 0!=windowHandle || !visible ) { - return 0 != windowHandle ; - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.createNative() START ("+getThreadName()+", "+this+")"); - } - if(validateParentWindowHandle()) { - if(!screenReferenced) { - screenReferenced = true; - screen.addReference(); - } - createNativeImpl(); - setVisibleImpl(true); - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.createNative() END ("+getThreadName()+", "+this+")"); - } - return 0 != windowHandle ; - } - - private boolean validateParentWindowHandle() { - if(null!=parentNativeWindow) { - parentWindowHandle = getNativeWindowHandle(parentNativeWindow); - return 0 != parentWindowHandle ; - } - return true; - } - - private static long getNativeWindowHandle(NativeWindow nativeWindow) { - long handle = 0; - if(null!=nativeWindow) { - boolean locked=false; - try { - if( NativeWindow.LOCK_SURFACE_NOT_READY < nativeWindow.lockSurface() ) { - locked=true; - handle = nativeWindow.getWindowHandle(); - if(0==handle) { - throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+nativeWindow); - } - } - } catch (NativeWindowException nwe) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.getNativeWindowHandle: not successful yet: "+nwe); - } - } finally { - if(locked) { - nativeWindow.unlockSurface(); - } - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.getNativeWindowHandle: locked "+locked+", "+nativeWindow); - } - } - return handle; - } - - public void runOnEDTIfAvail(boolean wait, final Runnable task) { - Screen screen = getInnerWindow().getScreen(); - if(null==screen) { - throw new RuntimeException("Null screen of inner class: "+this); - } - Display d = screen.getDisplay(); - d.runOnEDTIfAvail(wait, task); - } - - /** - * Create native windowHandle, ie creates a new native invisible window. - */ - protected abstract void createNativeImpl(); - - protected abstract void closeNativeImpl(); - - public Capabilities getRequestedCapabilities() { - return (Capabilities)caps.clone(); - } - - public NativeWindow getParentNativeWindow() { - return parentNativeWindow; - } - - public Screen getScreen() { - return screen; - } - - public String toString() { - StringBuffer sb = new StringBuffer(); - - sb.append(getClass().getName()+"[Config "+config+ - "\n, "+screen+ - "\n, ParentWindow "+parentNativeWindow+ - "\n, ParentWindowHandle "+toHexString(parentWindowHandle)+ - "\n, WindowHandle "+toHexString(getWindowHandle())+ - "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ - "\n, Pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ - "\n, Visible "+isVisible()+ - "\n, Undecorated "+undecorated+ - "\n, Fullscreen "+fullscreen+ - "\n, WrappedWindow "+getWrappedWindow()+ - "\n, ChildWindows "+childWindows.size()); - - sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); - for (Iterator iter = surfaceUpdatedListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("], WindowListeners num "+windowListeners.size()+" ["); - for (Iterator iter = windowListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("], MouseListeners num "+mouseListeners.size()+" ["); - for (Iterator iter = mouseListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("], KeyListeners num "+keyListeners.size()+" ["); - for (Iterator iter = keyListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("] ]"); - return sb.toString(); - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - if (title == null) { - title = ""; - } - this.title = title; - if(0 != windowHandle) { - setTitleImpl(title); - } - } - protected void setTitleImpl(String title) {} - - public void setUndecorated(boolean value) { - undecorated = value; - } - - public boolean isUndecorated(boolean fullscreen) { - return 0 != parentWindowHandle || undecorated || fullscreen ; - } - - public boolean isUndecorated() { - return 0 != parentWindowHandle || undecorated || fullscreen ; - } - - public void requestFocus() { - enqueueRequestFocus(false); // FIXME: or shall we wait ? - } - protected void requestFocusImpl() {} - - class RequestFocusAction implements Runnable { - public void run() { - Window.this.requestFocusImpl(); - } - } - RequestFocusAction requestFocusAction = new RequestFocusAction(); - - public void enqueueRequestFocus(boolean wait) { - runOnEDTIfAvail(wait, requestFocusAction); - } - - /** - * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. - * This allows notifying a covered window toolkit like AWT that the focus is requested, - * hence focus traversal can be made transparent. - */ - public void setFocusAction(FocusRunnable focusAction) { - this.focusAction = focusAction; - } - protected boolean focusAction() { - if(null!=focusAction) { - return focusAction.run(); - } - return false; - } - protected FocusRunnable focusAction = null; - - public static interface FocusRunnable { - /** - * @return false if NEWT shall proceed requesting the focus, - * true if NEWT shall not request the focus. - */ - public boolean run(); - } // - // NativeWindow impl + // Lifecycle // - /** Recursive and blocking lockSurface() implementation */ - public int lockSurface() { - // We leave the ToolkitLock lock to the specializtion's discretion, - // ie the implicit JAWTWindow in case of AWTWindow - - windowLock.lock(); - - // if(windowLock.getRecursionCount() == 0) { // allow recursion to lock again, always - if(!isNativeValid()) { - windowLock.unlock(); - return LOCK_SURFACE_NOT_READY; - } - // } - return LOCK_SUCCESS; - } - - /** Recursive and unblocking unlockSurface() implementation */ - public void unlockSurface() throws NativeWindowException { - windowLock.unlock(); - // We leave the ToolkitLock unlock to the specializtion's discretion, - // ie the implicit JAWTWindow in case of AWTWindow - } - - public boolean isSurfaceLocked() { - return windowLock.isLocked(); - } - - public Thread getSurfaceLockOwner() { - return windowLock.getOwner(); - } - - public Exception getLockedStack() { - return windowLock.getLockedStack(); - } - - /** - * <p> - * destroys the window and children and releases - * windowing related resources.<br></p> - * <p> - * all other resources and states are kept intact, - * ie listeners, parent handles, size, position and Screen reference.<br></p> + /** + * @return True if native window is valid, can be created or recovered. + * Otherwise false, ie this window is unrecoverable due to a <code>destroy(true)</code> call. * * @see #destroy(boolean) - * @see #invalidate() - */ - public final void destroy() { - destroy(false); - } - - /** - * Destroys the Window and it's children. - * @param unrecoverable If true, all resources, ie listeners, parent handles, - * size, position and reference to it's Screen will be destroyed as well. - * Otherwise you can recreate the window, via <code>setVisible(true)</code>. - * @see #destroy() - * @see #invalidate(boolean) * @see #setVisible(boolean) */ - public void destroy(boolean unrecoverable) { - if(isValid()) { - if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window.destroy(unrecoverable: "+unrecoverable+") START "+getThreadName()+", "+this); - //System.err.println(msg); - Exception ee = new Exception(msg); - ee.printStackTrace(); - } - runOnEDTIfAvail(true, new DestroyAction(unrecoverable)); - } - } - - class DestroyAction implements Runnable { - boolean unrecoverable; - public DestroyAction(boolean unrecoverable) { - this.unrecoverable = unrecoverable; - } - public void run() { - windowLock(); - try { - // Childs first .. - synchronized(childWindowsLock) { - for(Iterator i = childWindows.iterator(); i.hasNext(); ) { - NativeWindow nw = (NativeWindow) i.next(); - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") CHILD BEGIN"); - if(nw instanceof Window) { - ((Window)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - if(unrecoverable) { - ((Window)nw).destroy(unrecoverable); - } - } else { - nw.destroy(); - } - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") CHILD END"); - } - } - - // Now us .. - if(unrecoverable) { - synchronized(childWindowsLock) { - childWindows = new ArrayList(); - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList(); - } - windowListeners = new ArrayList(); - mouseListeners = new ArrayList(); - keyListeners = new ArrayList(); - } - if( null != screen && 0 != windowHandle ) { - closeNativeImpl(); - } - invalidate(unrecoverable); - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") END "+getThreadName()+", "+Window.this); - } - } finally { - windowUnlock(); - } - } - } - - /** - * <p> - * render all native window information invalid, - * as if the native window was destroyed.<br></p> - * <p> - * all other resources and states are kept intact, - * ie listeners, parent handles and size, position etc.<br></p> - * - * @see #destroy() - * @see #destroy(boolean) - * @see #invalidate(boolean) - */ - public void invalidate() { - invalidate(false); - } + boolean isValid(); /** - * @param unrecoverable If true, all states, size, position, parent handles, - * reference to it's Screen are reset. - * Otherwise you can recreate the window, via <code>setVisible(true)</code>. - * @see #invalidate() - * @see #destroy() - * @see #destroy(boolean) - */ - protected void invalidate(boolean unrecoverable) { - windowLock(); - try{ - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - String msg = new String("!!! Window Invalidate(unrecoverable: "+unrecoverable+") "+getThreadName()); - System.err.println(msg); - // Exception e = new Exception(msg); - // e.printStackTrace(); - } - windowHandle = 0; - visible = false; - fullscreen = false; - - if(unrecoverable) { - System.err.println("Window.invalidate: 1 "+screen); - if(null!=screen) { - screenReferenced = false; - screen.removeReference(); - } - screen = null; - System.err.println("Window.invalidate: 2 "+screen); - parentWindowHandle = 0; - parentNativeWindow = null; - caps = null; - - // Default position and dimension will be re-set immediately by user - width = 128; - height = 128; - x=0; - y=0; - } - } finally { - windowUnlock(); - } - } - - /** @return true if the native window handle is valid and ready to operate, ie - * if the native window has been created, otherwise false. + * @return true if the native window handle is valid and ready to operate, ie + * if the native window has been created, otherwise false. * * @see #setVisible(boolean) * @see #destroy(boolean) */ - public boolean isNativeValid() { - return null != screen && 0 != windowHandle ; - } - - /** @return True if native window is valid, can be created or recovered. - * Otherwise false, ie this window is unrecoverable due to a <code>destroy(true)</code> call. - * - * @see #destroy(boolean) - * @see #setVisible(boolean) - */ - public boolean isValid() { - return null != screen ; - } - - public boolean surfaceSwap() { - return false; - } - - public long getDisplayHandle() { - return screen.getDisplay().getHandle(); - } - - public int getScreenIndex() { - return screen.getIndex(); - } - - public long getWindowHandle() { - return windowHandle; - } - - public long getSurfaceHandle() { - return windowHandle; // default: return window handle - } - - public AbstractGraphicsConfiguration getGraphicsConfiguration() { - return config; - } + boolean isNativeValid(); /** - * Returns the width of the client area of this window - * @return width of the client area + * @return The associated Screen */ - public int getWidth() { - return width; - } + Screen getScreen(); /** - * Returns the height of the client area of this window - * @return height of the client area + * @return The NativeWindow representation of the parent Window, + * or null if this Window is top level */ - public int getHeight() { - return height; - } + NativeWindow getParentNativeWindow(); /** - * Returns the insets for this native window (the difference between the - * size of the toplevel window with the decorations and the client area). - * - * @return insets for this platform window + * @return The requested capabilities */ - // this probably belongs to NativeWindow interface - public Insets getInsets() { - return new Insets(0,0,0,0); - } + Capabilities getRequestedCapabilities(); - /** Returns the most inner Window instance.<br> - Currently only {@link com.jogamp.newt.opengl.GLWindow} - has an aggregation to an inner Window instance. - */ - public Window getInnerWindow() { - return this; - } - - /** If this Window actually wraps one from another toolkit such as - the AWT, this will return a non-null value. */ - public Object getWrappedWindow() { - return null; - } - - // - // Additional methods - // - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public boolean isVisible() { - return visible; - } - - public boolean isFullscreen() { - return fullscreen; - } - - private boolean handleDestroyNotify = true; - - /** If the implementation is capable of detecting a device change - return true and clear the status/reason of the change. */ - public boolean hasDeviceChanged() { - return false; - } - - class ReparentAction implements Runnable { - /** No native reparenting action */ - static final int ACTION_NONE = 0; - - /** Change Window tree only */ - static final int ACTION_SOFT_REPARENTING = 1; - - /** Native reparenting incl. Window tree */ - static final int ACTION_NATIVE_REPARENTING = 2; - - /** Native window creation after tree change - instead of reparenting. */ - static final int ACTION_NATIVE_CREATION = 3; - - NativeWindow newParent; - public ReparentAction(NativeWindow newParent) { - this.newParent = newParent; - } - public void run() { - windowLock(); - try{ - Window newParentWindow = null; - if(newParent instanceof Window) { - newParentWindow = (Window) newParent; - } - - int reparentAction = -1; // ensure it's set - long newParentHandle = 0 ; - - if(null!=newParent) { - // Case: Child Window - newParentHandle = getNativeWindowHandle(newParent); - if(0 == newParentHandle) { - // Case: Parent's native window not realized yet - if(null==newParentWindow) { - throw new NativeWindowException("Parent not NEWT Window and not realized yet: "+newParent); - } - // Destroy this window (handle screen + native) and use parent's Screen. - // It may be created properly when the parent is made visible. - destroy(false); - screen = newParentWindow.getScreen(); - reparentAction = ACTION_SOFT_REPARENTING; - } else if(newParent != parentNativeWindow) { - // Case: Parent's native window realized and changed - if( !isNativeValid() ) { - // May create a new compatible Screen/Display and - // mark it for creation. - if(null!=newParentWindow) { - screen = newParentWindow.getScreen(); - } else { - Screen newScreen = NewtFactory.createCompatibleScreen(newParent, screen); - if( screen != newScreen ) { - // auto destroy on-the-fly created Screen/Display - newScreen.setDestroyWhenUnused(true); - screen = newScreen; - } - } - reparentAction = ACTION_NATIVE_CREATION; - } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || !NewtFactory.isScreenCompatible(newParent, screen) ) { - // Destroy this window (handle screen + native) and - // may create a new compatible Screen/Display and - // mark it for creation. - destroy(false); - if(null!=newParentWindow) { - screen = newParentWindow.getScreen(); - } else { - screen = NewtFactory.createCompatibleScreen(newParent, screen); - screen.setDestroyWhenUnused(true); - } - reparentAction = ACTION_NATIVE_CREATION; - } else { - // Mark it for native reparenting - reparentAction = ACTION_NATIVE_REPARENTING; - } - } else { - // Case: Parent's native window realized and not changed - reparentAction = ACTION_NONE; - } - } else { - // Case: Top Window - if( 0 == parentWindowHandle ) { - // Already Top Window - reparentAction = ACTION_NONE; - } else { - // Mark it for native reparenting - reparentAction = ACTION_NATIVE_REPARENTING; - } - } - - if ( ACTION_NONE > reparentAction ) { - throw new NativeWindowException("Internal Error: reparentAction not set"); - } - - if( ACTION_NONE == reparentAction ) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparent: NO CHANGE ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+", visible "+visible+", parentNativeWindow "+(null!=parentNativeWindow)); - } - return; - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparent: START ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+", reparentAction "+reparentAction+", visible "+visible+", parentNativeWindow "+(null!=parentNativeWindow)); - } - - // rearrange window tree - if(null!=parentNativeWindow && parentNativeWindow instanceof Window) { - ((Window)parentNativeWindow).getInnerWindow().removeChild(Window.this); - } - parentNativeWindow = newParent; - if(parentNativeWindow instanceof Window) { - ((Window)parentNativeWindow).getInnerWindow().addChild(Window.this); - } - - if( ACTION_SOFT_REPARENTING == reparentAction ) { - return; - } - - if( ACTION_NATIVE_REPARENTING == reparentAction ) { - Display display = screen.getDisplay(); - - parentWindowHandle = newParentHandle; - if(0!=parentWindowHandle) { - // reset position to 0/0 within parent space - // FIXME .. cache position ? - x = 0; - y = 0; - } - getScreen().getDisplay().dispatchMessages(); // status up2date - boolean wasVisible = isVisible(); - if(wasVisible) { - Window.this.visible = false; - setVisibleImpl(false); - display.dispatchMessages(); // status up2date - } - boolean ok = reparentWindowImpl(); - display.dispatchMessages(); // status up2date - if ( !ok ) { - // native reparent failed -> try creation - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparent: native reparenting failed ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+" - Trying recreation"); - } - destroy(false); - Window.this.visible = wasVisible; - reparentAction = ACTION_NATIVE_CREATION ; - } else { - if(wasVisible) { - Window.this.visible = true; - setVisibleImpl(true); - requestFocusImpl(); - display.dispatchMessages(); // status up2date - } - } - } - - // not-else: re-entrance via reparentAction value change possible - if( ACTION_NATIVE_CREATION == reparentAction ) { - if(isVisible()) { - setVisible(true); // native creation - screen.getDisplay().dispatchMessages(); // status up2date - } - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparentWindow: END ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentNativeWindow "+(null!=parentNativeWindow)); - } - } finally { - windowUnlock(); - } - } - } + Capabilities getChosenCapabilities(); /** - * Change this window's parent window.<br> - * <P> - * In case the old parent is not null and a Window, - * this window is removed from it's list of children.<br> - * In case the new parent is not null and a Window, - * this window is added to it's list of children.<br></P> * - * @param newParent The new parent NativeWindow. If null, this Window becomes a top level window. + * <p> + * destroys the window and children and releases + * windowing related resources.<br></p> + * <p> + * all other resources and states are kept intact, + * ie listeners, parent handles, size, position and Screen reference.<br></p> + * + * @see #destroy(boolean) + * @see #invalidate() */ - public void reparentWindow(NativeWindow newParent) { - if(isValid()) { - runOnEDTIfAvail(true, new ReparentAction(newParent)); - if( isVisible() ) { - sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener - windowRepaint(0, 0, getWidth(), getHeight()); - } - } - } + void destroy(); - class VisibleAction implements Runnable { - boolean visible; - public VisibleAction(boolean visible) { - this.visible = visible; - } - public void run() { - windowLock(); - try{ - if( isValid() ) { - if(!visible && childWindows.size()>0) { - synchronized(childWindowsLock) { - for(Iterator i = childWindows.iterator(); i.hasNext(); ) { - NativeWindow nw = (NativeWindow) i.next(); - if(nw instanceof Window) { - ((Window)nw).setVisible(false); - } - } - } - } - if(0==windowHandle && visible) { - Window.this.visible = visible; - if( 0<width*height ) { - createNative(); - } - } else if(Window.this.visible != visible) { - Window.this.visible = visible; - if(0 != windowHandle) { - setVisibleImpl(visible); - } - } - if(0!=windowHandle && visible && childWindows.size()>0) { - synchronized(childWindowsLock) { - for(Iterator i = childWindows.iterator(); i.hasNext(); ) { - NativeWindow nw = (NativeWindow) i.next(); - if(nw instanceof Window) { - ((Window)nw).setVisible(true); - } - } - } - } - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setVisible: END ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+Window.this.visible); - } - } finally { - windowUnlock(); - } - } - } + /** + * + * Destroys the Window and it's children. + * @param unrecoverable If true, all resources, ie listeners, parent handles, + * size, position and reference to it's Screen will be destroyed as well. + * Otherwise you can recreate the window, via <code>setVisible(true)</code>. + * @see #destroy() + * @see #invalidate(boolean) + * @see #setVisible(boolean) + */ + void destroy(boolean unrecoverable); /** * <p> @@ -889,14 +123,14 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * <p> * Zero size semantics are respected, see {@link #setSize(int,int)}:<br> * <pre> - * if ( 0 == windowHandle && visible ) { - * this.visible = visible; - * if( 0<width*height ) { - * createNative(); - * } + * if ( 0 == windowHandle && visible ) { + * this.visible = visible; + * if( 0<width*height ) { + * createNative(); + * } * } else if ( this.visible != visible ) { - * this.visible = visible; - * setNativeSizeImpl(); + * this.visible = visible; + * setNativeSizeImpl(); * } * </pre></p> * <p> @@ -905,18 +139,21 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * If this action fails, ie if the parent {@link javax.media.nativewindow.NativeWindow} is not valid yet,<br> * no native window is created yet and <code>setVisible(true)</code> shall be repeated when it is.<br></p> */ - public void setVisible(boolean visible) { - if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentNativeWindow "+(null!=parentNativeWindow)); - //System.err.println(msg); - Exception ee = new Exception(msg); - ee.printStackTrace(); - } - if(isValid()) { - runOnEDTIfAvail(true, new VisibleAction(visible)); - } - } - protected abstract void setVisibleImpl(boolean visible); + void setVisible(boolean visible); + + boolean isVisible(); + + // + // Child Window Management + // + + void addChild(NativeWindow win); + + void removeChild(NativeWindow win); + + // + // Modes / States + // /** * Sets the size of the client area of the window, excluding decorations @@ -926,11 +163,11 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * Zero size semantics are respected, see {@link #setVisible(boolean)}:<br> * <pre> * if ( 0 != windowHandle && 0>=width*height && visible ) { - * setVisible(false); + * setVisible(false); * } else if ( 0 == windowHandle && 0<width*height && visible ) { - * setVisible(true); + * setVisible(true); * } else { - * // as expected .. + * // as expected .. * } * </pre></p> * <p> @@ -939,48 +176,57 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * @param width of the client area of the window * @param height of the client area of the window */ - public void setSize(int width, int height) { - int visibleAction = 0; // 1 invisible, 2 visible - windowLock(); - try{ - if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window setSize: START "+this.width+"x"+this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible); - System.err.println(msg); - // Exception e = new Exception(msg); - // e.printStackTrace(); - } - if (width != this.width || this.height != height) { - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - if ( 0 != windowHandle && 0>=width*height && visible ) { - visibleAction=1; // invisible - this.width = 0; - this.height = 0; - } else if ( 0 == windowHandle && 0<width*height && visible ) { - visibleAction = 2; // visible - this.width = width; - this.height = height; - } else if ( 0 != windowHandle ) { - // this width/height will be set by windowChanged, called by the native implementation - setSizeImpl(width, height); - } else { - this.width = width; - this.height = height; - } - } - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setSize: END "+this.width+"x"+this.height+", visibleAction "+visibleAction); - } - } finally { - windowUnlock(); - } - if(visibleAction>0) { - setVisible( ( 1 == visibleAction ) ? false : true ); - } + void setSize(int width, int height); + + /** + * Returns the width of the client area of this window + * @return width of the client area + */ + int getWidth(); + + /** + * Returns the height of the client area of this window + * @return height of the client area + */ + int getHeight(); + + /** Defining ids for the reparenting strategy */ + public interface ReparentAction { + /** No native reparenting valid */ + static final int ACTION_INVALID = -1; + + /** No native reparenting action required, no change*/ + static final int ACTION_UNCHANGED = 0; + + /** Native reparenting incl. Window tree */ + static final int ACTION_NATIVE_REPARENTING = 1; + + /** Native window creation after tree change - instead of reparenting. */ + static final int ACTION_NATIVE_CREATION = 2; + + /** Change Window tree only, native creation is pending */ + static final int ACTION_NATIVE_CREATION_PENDING = 3; } - protected abstract void setSizeImpl(int width, int height); + + /** + * Change this window's parent window.<br> + * <P> + * In case the old parent is not null and a Window, + * this window is removed from it's list of children.<br> + * In case the new parent is not null and a Window, + * this window is added to it's list of children.<br></P> + * + * @param newParent The new parent NativeWindow. If null, this Window becomes a top level window. + * + * @return The issued reparent action type (strategy) as defined in Window.ReparentAction + */ + int reparentWindow(NativeWindow newParent); + + int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate); + + boolean setFullscreen(boolean fullscreen); + + boolean isFullscreen(); /** * Sets the location of the top left corner of the window, including @@ -992,774 +238,176 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * @param x coord of the top left corner * @param y coord of the top left corner */ - public void setPosition(int x, int y) { - windowLock(); - try{ - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)); - } - if ( this.x != x || this.y != y ) { - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - if(0!=windowHandle) { - // this x/y will be set by windowChanged, called by X11 - setPositionImpl(x, y); - } else { - this.x = x; - this.y = y; - } - } - } - } finally { - windowUnlock(); - } - } - protected abstract void setPositionImpl(int x, int y); - - public boolean setFullscreen(boolean fullscreen) { - windowLock(); - try{ - if(0!=windowHandle && this.fullscreen!=fullscreen) { - int x,y,w,h; - if(fullscreen) { - x = 0; y = 0; - w = screen.getWidth(); - h = screen.getHeight(); - } else { - if(0!=parentWindowHandle) { - x=0; - y=0; - } else { - x = nfs_x; - y = nfs_y; - } - w = nfs_width; - h = nfs_height; - } - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()); - } - this.fullscreen = fullscreen; - setFullscreenImpl(fullscreen, x, y, w, h); - } - } finally { - windowUnlock(); - } - if( isVisible() ) { - windowRepaint(0, 0, getWidth(), getHeight()); - } - return this.fullscreen; - } - protected abstract void setFullscreenImpl(boolean fullscreen, int x, int y, int widht, int height); + void setPosition(int x, int y); + + int getX(); - // - // Child Window Management - // + int getY(); - private ArrayList childWindows = new ArrayList(); - private Object childWindowsLock = new Object(); + /** + * Returns the insets for this native window (the difference between the + * size of the toplevel window with the decorations and the client area). + * + * @return insets for this platform window + */ + Insets getInsets(); - protected void removeChild(NativeWindow win) { - synchronized(childWindowsLock) { - childWindows.remove(win); - } - } + void setUndecorated(boolean value); + + boolean isUndecorated(); + + void setTitle(String title); - protected void addChild(NativeWindow win) { - if (win == null) { - return; - } - synchronized(childWindowsLock) { - childWindows.add(win); - } + String getTitle(); + + static interface FocusRunnable { + /** + * @return false if NEWT shall proceed requesting the focus, + * true if NEWT shall not request the focus. + */ + public boolean run(); } - // - // Generic Event Support - // - private void doEvent(boolean enqueue, boolean wait, com.jogamp.newt.event.NEWTEvent event) { - boolean done = false; + /** + * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. + * This allows notifying a covered window toolkit like AWT that the focus is requested, + * hence focus traversal can be made transparent. + */ + void setFocusAction(FocusRunnable focusAction); - if(!enqueue) { - done = consumeEvent(event); - wait = done; // don't wait if event can't be consumed now - } + void requestFocus(); - if(!done) { - enqueueEvent(wait, event); - } - } + void windowRepaint(int x, int y, int width, int height); - public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { - if(getInnerWindow().isValid()) { - getInnerWindow().getScreen().getDisplay().enqueueEvent(wait, event); - } - } + void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event); + + void runOnEDTIfAvail(boolean wait, final Runnable task); - public boolean consumeEvent(NEWTEvent e) { - switch(e.getEventType()) { - case WindowEvent.EVENT_WINDOW_REPAINT: - if( windowIsLocked() ) { - // make sure only one repaint event is queued - if(!repaintQueued) { - repaintQueued=true; - return false; - } - return true; - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowRepaint: "+e); - // Exception ee = new Exception("Window.windowRepaint: "+e); - // ee.printStackTrace(); - } - repaintQueued=false; // no repaint event queued - break; - default: - break; - } - if(e instanceof WindowEvent) { - getInnerWindow().consumeWindowEvent((WindowEvent)e); - } else if(e instanceof KeyEvent) { - getInnerWindow().consumeKeyEvent((KeyEvent)e); - } else if(e instanceof MouseEvent) { - getInnerWindow().consumeMouseEvent((MouseEvent)e); - } else { - throw new NativeWindowException("Unexpected NEWTEvent type " + e); - } - return true; - } - protected boolean repaintQueued = false; // - // SurfaceUpdatedListener Support + // SurfaceUpdateListener // - private ArrayList surfaceUpdatedListeners = new ArrayList(); - private Object surfaceUpdatedListenersLock = new Object(); - - /** - * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of + /** + * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of * the list. */ - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - getInnerWindow().addSurfaceUpdatedListener(-1, l); - } + void addSurfaceUpdatedListener(SurfaceUpdatedListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} at the * specified position in the list.<br> - - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) - throws IndexOutOfBoundsException - { - if(l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size(); - } - surfaceUpdatedListeners.add(index, l); - } - } + void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - if (l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners.remove(l); - } - } + void removeAllSurfaceUpdatedListener(); - public void removeAllSurfaceUpdatedListener() { - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList(); - } - } + void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); - public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size()-1; - } - return (SurfaceUpdatedListener) surfaceUpdatedListeners.get(index); - } - } + SurfaceUpdatedListener getSurfaceUpdatedListener(int index); - public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - synchronized(surfaceUpdatedListenersLock) { - return (SurfaceUpdatedListener[]) surfaceUpdatedListeners.toArray(); - } - } + SurfaceUpdatedListener[] getSurfaceUpdatedListeners(); - public void surfaceUpdated(Object updater, NativeWindow window, long when) { - synchronized(surfaceUpdatedListenersLock) { - for(Iterator i = surfaceUpdatedListeners.iterator(); i.hasNext(); ) { - SurfaceUpdatedListener l = (SurfaceUpdatedListener) i.next(); - l.surfaceUpdated(updater, window, when); - } - } - } // - // MouseListener/Event Support + // WindowListener // - private ArrayList mouseListeners = new ArrayList(); - private int mouseButtonPressed = 0; // current pressed mouse button number - private long lastMousePressed = 0; // last time when a mouse button was pressed - private int lastMouseClickCount = 0; // last mouse button click count - public static final int ClickTimeout = 300; - - public void sendMouseEvent(int eventType, int modifiers, - int x, int y, int button, int rotation) { - doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation); - } - public void enqueueMouseEvent(boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { - doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation); - } - private void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { - if(x<0||y<0||x>=width||y>=height) { - return; // .. invalid .. - } - if(DEBUG_MOUSE_EVENT) { - System.err.println("doMouseEvent: enqueue"+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+ - ", mod "+modifiers+", pos "+x+"/"+y+", button "+button); - } - if(button<0||button>MouseEvent.BUTTON_NUMBER) { - throw new NativeWindowException("Invalid mouse button number" + button); - } - long when = System.currentTimeMillis(); - MouseEvent eClicked = null; - MouseEvent e = null; - - if(MouseEvent.EVENT_MOUSE_PRESSED==eventType) { - if(when-lastMousePressed<ClickTimeout) { - lastMouseClickCount++; - } else { - lastMouseClickCount=1; - } - lastMousePressed=when; - mouseButtonPressed=button; - e = new MouseEvent(eventType, this, when, - modifiers, x, y, lastMouseClickCount, button, 0); - } else if(MouseEvent.EVENT_MOUSE_RELEASED==eventType) { - e = new MouseEvent(eventType, this, when, - modifiers, x, y, lastMouseClickCount, button, 0); - if(when-lastMousePressed<ClickTimeout) { - eClicked = new MouseEvent(MouseEvent.EVENT_MOUSE_CLICKED, this, when, - modifiers, x, y, lastMouseClickCount, button, 0); - } else { - lastMouseClickCount=0; - lastMousePressed=0; - } - mouseButtonPressed=0; - } else if(MouseEvent.EVENT_MOUSE_MOVED==eventType) { - if (mouseButtonPressed>0) { - e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when, - modifiers, x, y, 1, mouseButtonPressed, 0); - } else { - e = new MouseEvent(eventType, this, when, - modifiers, x, y, 0, button, 0); - } - } else if(MouseEvent.EVENT_MOUSE_WHEEL_MOVED==eventType) { - e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, rotation); - } else { - e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, 0); - } - doEvent(enqueue, wait, e); - if(null!=eClicked) { - if(DEBUG_MOUSE_EVENT) { - System.err.println("doMouseEvent: synthesized MOUSE_CLICKED event"); - } - doEvent(enqueue, wait, eClicked); - } - } + public void sendWindowEvent(int eventType); - /** - * Appends the given {@link com.jogamp.newt.event.MouseListener} to the end of + /** + * + * Appends the given {@link com.jogamp.newt.event.WindowListener} to the end of * the list. */ - public void addMouseListener(MouseListener l) { - getInnerWindow().addMouseListener(-1, l); - } + void addWindowListener(WindowListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.MouseListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.WindowListener} at the * specified position in the list.<br> - - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addMouseListener(int index, MouseListener l) { - if(l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); - if(0>index) { - index = clonedListeners.size(); - } - clonedListeners.add(index, l); - mouseListeners = clonedListeners; - } - - public void removeMouseListener(MouseListener l) { - if (l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); - clonedListeners.remove(l); - mouseListeners = clonedListeners; - } + void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException; - public MouseListener getMouseListener(int index) { - ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); - if(0>index) { - index = clonedListeners.size()-1; - } - return (MouseListener) clonedListeners.get(index); - } + void removeWindowListener(WindowListener l); - public MouseListener[] getMouseListeners() { - return (MouseListener[]) mouseListeners.toArray(); - } + WindowListener getWindowListener(int index); - protected void consumeMouseEvent(MouseEvent e) { - if(DEBUG_MOUSE_EVENT) { - System.err.println("consumeMouseEvent: event: "+e); - } - - for(Iterator i = mouseListeners.iterator(); i.hasNext(); ) { - MouseListener l = (MouseListener) i.next(); - switch(e.getEventType()) { - case MouseEvent.EVENT_MOUSE_CLICKED: - l.mouseClicked(e); - break; - case MouseEvent.EVENT_MOUSE_ENTERED: - l.mouseEntered(e); - break; - case MouseEvent.EVENT_MOUSE_EXITED: - l.mouseExited(e); - break; - case MouseEvent.EVENT_MOUSE_PRESSED: - l.mousePressed(e); - break; - case MouseEvent.EVENT_MOUSE_RELEASED: - l.mouseReleased(e); - break; - case MouseEvent.EVENT_MOUSE_MOVED: - l.mouseMoved(e); - break; - case MouseEvent.EVENT_MOUSE_DRAGGED: - l.mouseDragged(e); - break; - case MouseEvent.EVENT_MOUSE_WHEEL_MOVED: - l.mouseWheelMoved(e); - break; - default: - throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); - } - } - } + WindowListener[] getWindowListeners(); // - // KeyListener/Event Support + // KeyListener // - public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { - consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); - } - - public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { - enqueueEvent(wait, new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); - } - /** - * Appends the given {@link com.jogamp.newt.event.KeyListener} to the end of + /** + * + * Appends the given {@link com.jogamp.newt.event.KeyListener} to the end of * the list. */ - public void addKeyListener(KeyListener l) { - getInnerWindow().addKeyListener(-1, l); - } + void addKeyListener(KeyListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.KeyListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.KeyListener} at the * specified position in the list.<br> - - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addKeyListener(int index, KeyListener l) { - if(l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) keyListeners.clone(); - if(0>index) { - index = clonedListeners.size(); - } - clonedListeners.add(index, l); - keyListeners = clonedListeners; - } + void addKeyListener(int index, KeyListener l); - public void removeKeyListener(KeyListener l) { - if (l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) keyListeners.clone(); - clonedListeners.remove(l); - keyListeners = clonedListeners; - } + void removeKeyListener(KeyListener l); - public KeyListener getKeyListener(int index) { - ArrayList clonedListeners = (ArrayList) keyListeners.clone(); - if(0>index) { - index = clonedListeners.size()-1; - } - return (KeyListener) clonedListeners.get(index); - } + KeyListener getKeyListener(int index); - public KeyListener[] getKeyListeners() { - return (KeyListener[]) keyListeners.toArray(); - } + KeyListener[] getKeyListeners(); - private ArrayList keyListeners = new ArrayList(); - - protected void consumeKeyEvent(KeyEvent e) { - if(DEBUG_KEY_EVENT) { - System.err.println("consumeKeyEvent: "+e); - } - for(Iterator i = keyListeners.iterator(); i.hasNext(); ) { - KeyListener l = (KeyListener) i.next(); - switch(e.getEventType()) { - case KeyEvent.EVENT_KEY_PRESSED: - l.keyPressed(e); - break; - case KeyEvent.EVENT_KEY_RELEASED: - l.keyReleased(e); - break; - case KeyEvent.EVENT_KEY_TYPED: - l.keyTyped(e); - break; - default: - throw new NativeWindowException("Unexpected key event type " + e.getEventType()); - } - } - } // - // WindowListener/Event Support + // MouseListener // - public void sendWindowEvent(int eventType) { - consumeWindowEvent( new WindowEvent(eventType, this, System.currentTimeMillis()) ); - } - - public void enqueueWindowEvent(boolean wait, int eventType) { - enqueueEvent( wait, new WindowEvent(eventType, this, System.currentTimeMillis()) ); - } - private ArrayList windowListeners = new ArrayList(); - - /** - * Appends the given {@link com.jogamp.newt.event.WindowListener} to the end of + /** + * + * Appends the given {@link com.jogamp.newt.event.MouseListener} to the end of * the list. */ - public void addWindowListener(WindowListener l) { - getInnerWindow().addWindowListener(-1, l); - } + void addMouseListener(MouseListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.WindowListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.MouseListener} at the * specified position in the list.<br> - - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addWindowListener(int index, WindowListener l) - throws IndexOutOfBoundsException - { - if(l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) windowListeners.clone(); - if(0>index) { - index = clonedListeners.size(); - } - clonedListeners.add(index, l); - windowListeners = clonedListeners; - } + void addMouseListener(int index, MouseListener l); - public void removeWindowListener(WindowListener l) { - if (l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) windowListeners.clone(); - clonedListeners.remove(l); - windowListeners = clonedListeners; - } - - public WindowListener getWindowListener(int index) { - ArrayList clonedListeners = (ArrayList) windowListeners.clone(); - if(0>index) { - index = clonedListeners.size()-1; - } - return (WindowListener) clonedListeners.get(index); - } + void removeMouseListener(MouseListener l); - public WindowListener[] getWindowListeners() { - return (WindowListener[]) windowListeners.toArray(); - } - - protected void consumeWindowEvent(WindowEvent e) { - if(DEBUG_WINDOW_EVENT) { - System.err.println("consumeWindowEvent: "+e); - } - for(Iterator i = windowListeners.iterator(); i.hasNext(); ) { - WindowListener l = (WindowListener) i.next(); - switch(e.getEventType()) { - case WindowEvent.EVENT_WINDOW_RESIZED: - l.windowResized(e); - break; - case WindowEvent.EVENT_WINDOW_MOVED: - l.windowMoved(e); - break; - case WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY: - l.windowDestroyNotify(e); - break; - case WindowEvent.EVENT_WINDOW_GAINED_FOCUS: - l.windowGainedFocus(e); - break; - case WindowEvent.EVENT_WINDOW_LOST_FOCUS: - l.windowLostFocus(e); - break; - case WindowEvent.EVENT_WINDOW_REPAINT: - l.windowRepaint((WindowUpdateEvent)e); - break; - default: - throw - new NativeWindowException("Unexpected window event type " - + e.getEventType()); - } - } - } + MouseListener getMouseListener(int index); - /** - * @param focusGained - */ - protected void focusChanged(boolean focusGained) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.focusChanged: "+focusGained); - } - if (focusGained) { - sendWindowEvent(WindowEvent.EVENT_WINDOW_GAINED_FOCUS); - } else { - sendWindowEvent(WindowEvent.EVENT_WINDOW_LOST_FOCUS); - } - } - - protected void visibleChanged(boolean visible) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); - // Exception e = new Exception("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); - // e.printStackTrace(); - } - this.visible = visible ; - } + MouseListener[] getMouseListeners(); - protected void sizeChanged(int newWidth, int newHeight) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.sizeChanged: "+width+"x"+height+" -> "+newWidth+"x"+newHeight); - } - if(width != newWidth || height != newHeight) { - width = newWidth; - height = newHeight; - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - } - sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); - } - } - - protected void positionChanged(int newX, int newY) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.positionChanged: "+x+"/"+y+" -> "+newX+"/"+newY); - } - if( 0==parentWindowHandle && ( x != newX || y != newY ) ) { - x = newX; - y = newY; - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - } - sendWindowEvent(WindowEvent.EVENT_WINDOW_MOVED); - } - } - - /** - * If set to true, the default value, this NEWT Window implementation will - * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.<br> - * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify()}. - */ - public void setHandleDestroyNotify(boolean b) { - handleDestroyNotify = b; - } - - protected void windowDestroyNotify() { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyNotify START "+getThreadName()); - } - - enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - - if(handleDestroyNotify && isValid()) { - destroy(); - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyeNotify END "+getThreadName()); - } - } - - protected void windowDestroyed() { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyed "+getThreadName()); - } - invalidate(); - } - - public boolean getPropagateRepaint() { - return propagateRepaint; - } - public void setPropagateRepaint(boolean v) { - propagateRepaint = v; - } - protected boolean propagateRepaint = true; - - public void windowRepaint(int x, int y, int width, int height) { - if(!propagateRepaint) { - return; - } - if(0>width) { - width=this.width; - } - if(0>height) { - height=this.height; - } - - NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(), - new Rectangle(x, y, width, height)); - doEvent(false, false, e); - } - - protected boolean reparentWindowImpl() { - // default implementation, no native reparenting support - return false; - } - - // - // Reflection helper .. - // - - private static Class[] getCustomConstructorArgumentTypes(Class windowClass) { - Class[] argTypes = null; - try { - Method m = windowClass.getDeclaredMethod("getCustomConstructorArgumentTypes", new Class[] {}); - argTypes = (Class[]) m.invoke(null, null); - } catch (Throwable t) {} - return argTypes; - } - - private static int verifyConstructorArgumentTypes(Class[] types, Object[] args) { - if(types.length != args.length) { - return -1; - } - for(int i=0; i<args.length; i++) { - if(!types[i].isInstance(args[i])) { - return i; - } - } - return args.length; - } - - private static String getArgsStrList(Object[] args) { - StringBuffer sb = new StringBuffer(); - for(int i=0; i<args.length; i++) { - sb.append(args[i].getClass()); - if(i<args.length) { - sb.append(", "); - } - } - return sb.toString(); - } - - private static String getTypeStrList(Class[] types) { - StringBuffer sb = new StringBuffer(); - for(int i=0; i<types.length; i++) { - sb.append(types[i]); - if(i<types.length) { - sb.append(", "); - } - } - return sb.toString(); - } - - protected RecursiveToolkitLock windowLock = new RecursiveToolkitLock(); - - private static final boolean TRACE_LOCK = false; - - protected final void windowLock() { - getInnerWindow().windowLock.lock(); - if(TRACE_LOCK) { - Exception e = new Exception("WINDOW LOCK SET: R "+getInnerWindow().windowLock.getRecursionCount()+", "+getInnerWindow().windowLock); - e.printStackTrace(); - } - } - protected final void windowUnlock() { - getInnerWindow().windowLock.unlock(); - if(TRACE_LOCK) { - Exception e = new Exception("WINDOW LOCK FREE: R "+getInnerWindow().windowLock.getRecursionCount()+", "+getInnerWindow().windowLock); - e.printStackTrace(); - } - } - protected final boolean windowIsLocked() { - return getInnerWindow().windowLock.isLocked(); - } - protected RecursiveToolkitLock getWindowLock() { - return getInnerWindow().windowLock; - } - protected final void shouldNotCallThis() { - throw new NativeWindowException("Should not call this"); - } - - public static String getThreadName() { - return Display.getThreadName(); - } - - public static String toHexString(int hex) { - return Display.toHexString(hex); - } - - public static String toHexString(long hex) { - return Display.toHexString(hex); - } } - diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 51b218aec..fdb434889 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -29,14 +29,12 @@ package com.jogamp.newt.awt; +import com.jogamp.newt.Display; import java.lang.reflect.*; import java.security.*; -import java.awt.Button; import java.awt.Canvas; -import java.awt.Component; import java.awt.EventQueue; -import java.awt.Frame; import java.awt.Graphics; import javax.media.nativewindow.*; @@ -44,12 +42,7 @@ import javax.media.nativewindow.*; import com.jogamp.newt.event.awt.AWTAdapter; import com.jogamp.newt.event.awt.AWTParentWindowAdapter; import com.jogamp.newt.event.WindowEvent; -import com.jogamp.newt.event.WindowAdapter; -import com.jogamp.newt.event.MouseEvent; -import com.jogamp.newt.event.MouseAdapter; -import com.jogamp.newt.Screen; import com.jogamp.newt.Window; -import com.jogamp.newt.NewtFactory; import com.jogamp.newt.impl.Debug; public class NewtCanvasAWT extends java.awt.Canvas { @@ -92,7 +85,7 @@ public class NewtCanvasAWT extends java.awt.Canvas { public final boolean result = false; // NEWT shall always proceed requesting the native focus public void run() { if(DEBUG) { - System.err.println("FocusActionImpl.run() "+Window.getThreadName()); + System.err.println("FocusActionImpl.run() "+Display.getThreadName()); } NewtCanvasAWT.this.requestFocusAWTParent(); } @@ -120,7 +113,7 @@ public class NewtCanvasAWT extends java.awt.Canvas { return newtChild; } - /** @return this AWT Canvas NativeWindow represention, may be null in case {@link #removeNotify()} has been called, + /** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called, * or {@link #addNotify()} hasn't been called yet.*/ public NativeWindow getNativeWindow() { return parent; } diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java index b28d41f7c..7b9130188 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java @@ -29,23 +29,12 @@ package com.jogamp.newt.awt; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.Component; -import java.awt.Canvas; -import javax.media.opengl.*; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; -import com.jogamp.newt.event.awt.AWTParentWindowAdapter; -import com.jogamp.newt.Display; -import com.jogamp.newt.Screen; -import com.jogamp.newt.Window; import com.jogamp.newt.NewtFactory; -import com.jogamp.newt.util.EDTUtil; import com.jogamp.newt.impl.Debug; -import com.jogamp.common.util.ReflectionUtil; public class NewtFactoryAWT extends NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); diff --git a/src/newt/classes/com/jogamp/newt/event/WindowListener.java b/src/newt/classes/com/jogamp/newt/event/WindowListener.java index 1a10131f7..174d4a414 100644 --- a/src/newt/classes/com/jogamp/newt/event/WindowListener.java +++ b/src/newt/classes/com/jogamp/newt/event/WindowListener.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -36,10 +37,21 @@ package com.jogamp.newt.event; import com.jogamp.newt.*; public interface WindowListener extends NEWTEventListener { + /** Window is resized, your application shall respect the new window dimension. A repaint is recommended. */ public void windowResized(WindowEvent e); + + /** Window has been moved. */ public void windowMoved(WindowEvent e); + + /** Window will be destroyed. Release of resources is recommended. */ public void windowDestroyNotify(WindowEvent e); + + /** Window gained focus. */ public void windowGainedFocus(WindowEvent e); + + /** Window lost focus. */ public void windowLostFocus(WindowEvent e); + + /** Window area shall be repainted. */ public void windowRepaint(WindowUpdateEvent e); } diff --git a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java new file mode 100644 index 000000000..4f839ed42 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.newt.impl; + +import com.jogamp.newt.*; +import javax.media.nativewindow.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.impl.event.*; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.newt.util.MainThread; +import java.util.*; + +public abstract class DisplayImpl extends Display { + public static final boolean DEBUG_TEST_EDT_MAINTHREAD = Debug.isPropertyDefined("newt.test.EDTMainThread", true); // JAU EDT Test .. + + private static int serialno = 1; + + private static Class getDisplayClass(String type) + throws ClassNotFoundException + { + Class displayClass = NewtFactory.getCustomClass(type, "Display"); + if(null==displayClass) { + if (NativeWindowFactory.TYPE_EGL.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDDisplay"); + } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.windows.WindowsDisplay"); + } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.macosx.MacDisplay"); + } else if (NativeWindowFactory.TYPE_X11.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.x11.X11Display"); + } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.awt.AWTDisplay"); + } else { + throw new RuntimeException("Unknown display type \"" + type + "\""); + } + } + return displayClass; + } + + /** Make sure to reuse a Display with the same name */ + public static DisplayImpl create(String type, String name, final long handle) { + try { + Class displayClass = getDisplayClass(type); + DisplayImpl display = (DisplayImpl) displayClass.newInstance(); + name = display.validateDisplayName(name, handle); + display.name = name; + display.type=type; + display.destroyWhenUnused=false; + synchronized(displayList) { + display.id = serialno++; + display.fqname = getFQName(display.id, display.type, display.name); + displayList.add(display); + } + display.createEDTUtil(); + if(DEBUG) { + System.err.println("Display.create() NEW: "+display+" "+getThreadName()); + } + return display; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected synchronized final void createNative() { + if(null==aDevice) { + if(DEBUG) { + System.err.println("Display.createNative() START ("+getThreadName()+", "+this+")"); + } + final DisplayImpl f_dpy = this; + runOnEDTIfAvail(true, new Runnable() { + public void run() { + f_dpy.createNativeImpl(); + }}); + if(null==aDevice) { + throw new RuntimeException("Display.createNative() failed to instanciate an AbstractGraphicsDevice"); + } + if(DEBUG) { + System.err.println("Display.createNative() END ("+getThreadName()+", "+this+")"); + } + synchronized(displayList) { + displaysActive++; + } + } + } + + protected boolean shallRunOnEDT() { + return true; + } + + protected void createEDTUtil() { + if(NewtFactory.useEDT()) { + if ( ! DEBUG_TEST_EDT_MAINTHREAD ) { + Thread current = Thread.currentThread(); + edtUtil = new DefaultEDTUtil(current.getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable); + } else { + // Begin JAU EDT Test .. + MainThread.addPumpMessage(this, dispatchMessagesRunnable); + edtUtil = MainThread.getSingleton(); + // End JAU EDT Test .. + } + if(DEBUG) { + System.err.println("Display.createNative("+getFQName()+") Create EDTUtil: "+edtUtil.getClass().getName()); + } + } + } + + public final EDTUtil getEDTUtil() { + return edtUtil; + } + + private void stopEDT(final Runnable task) { + if( shallRunOnEDT() && null!=edtUtil ) { + edtUtil.invokeStop(task); + } else { + task.run(); + } + } + + public void runOnEDTIfAvail(boolean wait, final Runnable task) { + if( shallRunOnEDT() && null!=edtUtil ) { + edtUtil.invoke(wait, task); + } else { + task.run(); + } + } + + public synchronized final void destroy() { + if ( null != aDevice ) { + if(DEBUG) { + dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); + } + synchronized(displayList) { + displayList.remove(this); + displaysActive--; + } + if(DEBUG) { + System.err.println("Display.destroy(): "+this+" "+getThreadName()); + } + final DisplayImpl f_dpy = this; + final EDTUtil f_edtUtil = edtUtil; + stopEDT( new Runnable() { + public void run() { + f_dpy.closeNativeImpl(); + } + } ); + if(null!=edtUtil) { + if ( DEBUG_TEST_EDT_MAINTHREAD ) { + MainThread.removePumpMessage(this); // JAU EDT Test .. + } + edtUtil.waitUntilStopped(); + edtUtil.reset(); + } + aDevice = null; + if(DEBUG) { + dumpDisplayList("Display.destroy("+getFQName()+") END"); + } + } + } + + protected synchronized final int addReference() { + if(DEBUG) { + System.err.println("Display.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); + } + if ( 0 == refCount ) { + createNative(); + } + if(null == aDevice) { + throw new RuntimeException("Display.addReference() (refCount "+refCount+") null AbstractGraphicsDevice"); + } + return ++refCount; + } + + + protected synchronized final int removeReference() { + if(DEBUG) { + System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + } + refCount--; + if(0==refCount && destroyWhenUnused) { + destroy(); + } + return refCount; + } + + public synchronized final int getReferenceCount() { + return refCount; + } + + public final boolean getDestroyWhenUnused() { return destroyWhenUnused; } + public final void setDestroyWhenUnused(boolean v) { destroyWhenUnused=v; } + + protected abstract void createNativeImpl(); + protected abstract void closeNativeImpl(); + + public final int getId() { + return id; + } + + public final String getType() { + return type; + } + + public final String getName() { + return name; + } + + public final String getFQName() { + return fqname; + } + + public static final String nilString = "nil" ; + + public String validateDisplayName(String name, long handle) { + if(null==name && 0!=handle) { + name="wrapping-"+toHexString(handle); + } + return ( null == name ) ? nilString : name ; + } + + public static final String getFQName(int id, String type, String name) { + if(null==type) type=nilString; + if(null==name) name=nilString; + StringBuffer sb = new StringBuffer(); + sb.append(type); + sb.append("_"); + sb.append(name); + sb.append("-"); + sb.append(id); + return sb.toString(); + } + + public final long getHandle() { + if(null!=aDevice) { + return aDevice.getHandle(); + } + return 0; + } + + public final AbstractGraphicsDevice getGraphicsDevice() { + return aDevice; + } + + public final boolean isNativeValid() { + return null != aDevice; + } + + public boolean isEDTRunning() { + if(null!=edtUtil) { + return edtUtil.isRunning(); + } + return false; + } + + public String toString() { + return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; + } + + protected abstract void dispatchMessagesNative(); + + private Object eventsLock = new Object(); + private LinkedList/*<NEWTEvent>*/ events = new LinkedList(); + + class DispatchMessagesRunnable implements Runnable { + public void run() { + DisplayImpl.this.dispatchMessages(); + } + } + DispatchMessagesRunnable dispatchMessagesRunnable = new DispatchMessagesRunnable(); + + public void dispatchMessages() { + // System.err.println("Display.dispatchMessages() 0 "+this+" "+getThreadName()); + if(0==refCount) return; // no screens + if(null==getGraphicsDevice()) return; // no native device + + LinkedList/*<NEWTEvent>*/ _events = null; + + if(!events.isEmpty()) { + // swap events list to free ASAP + synchronized(eventsLock) { + if(!events.isEmpty()) { + _events = events; + events = new LinkedList(); + } + eventsLock.notifyAll(); + } + if( null != _events ) { + for (Iterator iter = _events.iterator(); iter.hasNext(); ) { + NEWTEventTask eventTask = (NEWTEventTask) iter.next(); + NEWTEvent event = eventTask.get(); + Object source = event.getSource(); + if(source instanceof NEWTEventConsumer) { + NEWTEventConsumer consumer = (NEWTEventConsumer) source ; + if(!consumer.consumeEvent(event)) { + enqueueEvent(false, event); + } + } else { + throw new RuntimeException("Event source not NEWT: "+source.getClass().getName()+", "+source); + } + eventTask.notifyIssuer(); + } + } + } + + // lock(); + try { + // System.err.println("Display.dispatchMessages() NATIVE "+this+" "+getThreadName()); + dispatchMessagesNative(); + } finally { + // unlock(); + // System.err.println("Display.dispatchMessages() X "+this+" "+getThreadName()); + } + } + + public void enqueueEvent(boolean wait, NEWTEvent e) { + Object lock = new Object(); + NEWTEventTask eTask = new NEWTEventTask(e, wait?lock:null); + synchronized(lock) { + synchronized(eventsLock) { + events.addLast(eTask); + eventsLock.notifyAll(); + } + if( wait ) { + try { + lock.wait(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + } + } + } + + public void lock() { + aDevice.lock(); + } + + public void unlock() { + aDevice.unlock(); + } + + protected EDTUtil edtUtil = null; + protected int id; + protected String name; + protected String type; + protected String fqname; + protected int refCount; // number of Display references by Screen + protected boolean destroyWhenUnused; + protected AbstractGraphicsDevice aDevice; +} + diff --git a/src/newt/classes/com/jogamp/newt/OffscreenWindow.java b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java index d17f8df07..217d9d293 100644 --- a/src/newt/classes/com/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -31,11 +32,11 @@ * */ -package com.jogamp.newt; +package com.jogamp.newt.impl; import javax.media.nativewindow.*; -public class OffscreenWindow extends Window implements SurfaceChangeable { +public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { long surfaceHandle = 0; @@ -45,20 +46,20 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { static long nextWindowHandle = 0x100; // start here - a marker protected void createNativeImpl() { - if(0!=parentWindowHandle) { + if(0!=getParentWindowHandle()) { throw new NativeWindowException("OffscreenWindow does not support window parenting"); } if(caps.isOnscreen()) { throw new NativeWindowException("Capabilities is onscreen"); } - AbstractGraphicsScreen aScreen = screen.getGraphicsScreen(); + AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); config = GraphicsConfigurationFactory.getFactory(aScreen.getDevice()).chooseGraphicsConfiguration(caps, null, aScreen); if (config == null) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } synchronized(OffscreenWindow.class) { - windowHandle = nextWindowHandle++; + setWindowHandle(nextWindowHandle++); } } @@ -66,12 +67,13 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { // nop } - public void invalidate() { - super.invalidate(); + public void invalidate(boolean unrecoverable) { + super.invalidate(unrecoverable); surfaceHandle = 0; } - public synchronized void destroy(boolean deep) { + public synchronized void destroy(boolean unrecoverable) { + super.destroy(unrecoverable); surfaceHandle = 0; } @@ -86,6 +88,9 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { protected void setVisibleImpl(boolean visible) { } + protected void requestFocusImpl(boolean reparented) { + } + public void setSize(int width, int height) { if(!visible) { this.width = width; @@ -107,7 +112,7 @@ public class OffscreenWindow extends Window implements SurfaceChangeable { // nop return false; } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + protected void reconfigureWindowImpl(int x, int y, int width, int height) { shouldNotCallThis(); } } diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java new file mode 100644 index 000000000..0104b4a4c --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.newt.impl; + +import com.jogamp.newt.*; + +import javax.media.nativewindow.*; +import java.security.*; + +public abstract class ScreenImpl implements Screen { + + private static Class getScreenClass(String type) + throws ClassNotFoundException + { + Class screenClass = NewtFactory.getCustomClass(type, "Screen"); + if(null==screenClass) { + if (NativeWindowFactory.TYPE_EGL.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen"); + } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen"); + } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen"); + } else if (NativeWindowFactory.TYPE_X11.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen"); + } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen"); + } else { + throw new RuntimeException("Unknown window type \"" + type + "\""); + } + } + return screenClass; + } + + public static ScreenImpl create(String type, Display display, final int idx) { + try { + if(usrWidth<0 || usrHeight<0) { + usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); + usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); + if(usrWidth>0 || usrHeight>0) { + System.err.println("User screen size "+usrWidth+"x"+usrHeight); + } + } + Class screenClass = getScreenClass(type); + ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); + screen.display = (DisplayImpl) display; + screen.idx = idx; + return screen; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected synchronized final void createNative() { + if(null == aScreen) { + if(DEBUG) { + System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")"); + } + display.addReference(); + createNativeImpl(); + if(null == aScreen) { + throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen"); + } + if(DEBUG) { + System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+")"); + } + } + } + + public synchronized final void destroy() { + if ( null != aScreen ) { + closeNativeImpl(); + display.removeReference(); + aScreen = null; + } + } + + protected synchronized final int addReference() { + if(DEBUG) { + System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); + } + if ( 0 == refCount ) { + createNative(); + } + if(null == aScreen) { + throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen"); + } + return ++refCount; + } + + protected synchronized final int removeReference() { + if(DEBUG) { + System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + } + refCount--; + if(0==refCount && getDestroyWhenUnused()) { + destroy(); + } + return refCount; + } + + public synchronized final int getReferenceCount() { + return refCount; + } + + public final boolean getDestroyWhenUnused() { + return display.getDestroyWhenUnused(); + } + public final void setDestroyWhenUnused(boolean v) { + display.setDestroyWhenUnused(v); + } + + protected abstract void createNativeImpl(); + protected abstract void closeNativeImpl(); + + protected void setScreenSize(int w, int h) { + System.err.println("Detected screen size "+w+"x"+h); + width=w; height=h; + } + + public final Display getDisplay() { + return display; + } + + public final int getIndex() { + return idx; + } + + public final AbstractGraphicsScreen getGraphicsScreen() { + return aScreen; + } + + public final boolean isNativeValid() { + return null != aScreen; + } + + public final int getWidth() { + return (usrWidth>0) ? usrWidth : (width>0) ? width : 480; + } + + public final int getHeight() { + return (usrHeight>0) ? usrHeight : (height>0) ? height : 480; + } + + public String toString() { + return "NEWT-Screen[idx "+idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]"; + } + + protected DisplayImpl display; + protected int idx; + protected AbstractGraphicsScreen aScreen; + protected int refCount; // number of Screen references by Window + protected int width=-1, height=-1; // detected values: set using setScreenSize + protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight + private static AccessControlContext localACC = AccessController.getContext(); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java new file mode 100644 index 000000000..9111419fc --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java @@ -0,0 +1,1771 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright (c) 2010 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.newt.impl; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Display; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.*; +import com.jogamp.newt.util.*; + +import com.jogamp.common.util.*; +import javax.media.nativewindow.*; +import com.jogamp.nativewindow.util.Rectangle; +import com.jogamp.nativewindow.impl.RecursiveToolkitLock; +import com.jogamp.newt.impl.OffscreenWindow; + +import java.util.ArrayList; +import java.util.Iterator; +import java.lang.reflect.Method; + +public abstract class WindowImpl implements Window, NEWTEventConsumer +{ + public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); + + // Workaround for initialization order problems on Mac OS X + // between native Newt and (apparently) Fmod -- if Fmod is + // initialized first then the connection to the window server + // breaks, leading to errors from deep within the AppKit + public static void init(String type) { + if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + try { + getWindowClass(type); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // + // Construction Methods + // + + private static Class getWindowClass(String type) + throws ClassNotFoundException + { + Class windowClass = NewtFactory.getCustomClass(type, "Window"); + if(null==windowClass) { + if (NativeWindowFactory.TYPE_EGL.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDWindow"); + } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.windows.WindowsWindow"); + } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.macosx.MacWindow"); + } else if (NativeWindowFactory.TYPE_X11.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.x11.X11Window"); + } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.awt.AWTWindow"); + } else { + throw new NativeWindowException("Unknown window type \"" + type + "\""); + } + } + return windowClass; + } + + public static WindowImpl create(String type, NativeWindow parentWindow, long parentWindowHandle, Screen screen, Capabilities caps) { + try { + Class windowClass; + if(caps.isOnscreen()) { + windowClass = getWindowClass(type); + } else { + windowClass = OffscreenWindow.class; + } + WindowImpl window = (WindowImpl) windowClass.newInstance(); + window.invalidate(true); + window.parentWindow = parentWindow; + window.parentWindowHandle = parentWindowHandle; + window.screen = (ScreenImpl) screen; + window.caps = (Capabilities)caps.clone(); + window.setUndecorated(0!=parentWindowHandle); + return window; + } catch (Throwable t) { + t.printStackTrace(); + throw new NativeWindowException(t); + } + } + + public static WindowImpl create(String type, Object[] cstrArguments, Screen screen, Capabilities caps) { + try { + Class windowClass = getWindowClass(type); + Class[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass); + if(null==cstrArgumentTypes) { + throw new NativeWindowException("WindowClass "+windowClass+" doesn't support custom arguments in constructor"); + } + int argsChecked = verifyConstructorArgumentTypes(cstrArgumentTypes, cstrArguments); + if ( argsChecked < cstrArguments.length ) { + throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments)); + } + WindowImpl window = (WindowImpl) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; + window.invalidate(true); + window.screen = (ScreenImpl) screen; + window.caps = (Capabilities)caps.clone(); + return window; + } catch (Throwable t) { + throw new NativeWindowException(t); + } + } + + public static interface LifecycleHook { + /** + * Invoked after Window setVisible, + * allows allocating resources depending on the native Window. + * Called from EDT. + */ + void setVisibleAction(boolean visible, boolean nativeWindowCreated); + + /** + * Invoked before Window destroy action, + * allows releasing of resources depending on the native Window. + * Called from EDT. + */ + void destroyAction(boolean unrecoverable); + + /** Only informal, when starting reparenting */ + void reparentActionPre(); + + /** Only informal, when finishing reparenting */ + void reparentActionPost(int reparentActionType); + } + + private LifecycleHook lifecycleHook = null; + private RecursiveToolkitLock windowLock = new RecursiveToolkitLock(); + private long windowHandle; + private ScreenImpl screen; + private boolean screenReferenced = false; + private NativeWindow parentWindow; + private long parentWindowHandle; + + protected AbstractGraphicsConfiguration config; + protected Capabilities caps; + protected boolean fullscreen, visible; + protected int width, height, x, y; + + // non fullscreen dimensions .. + protected int nfs_width, nfs_height, nfs_x, nfs_y; + + protected String title = "Newt Window"; + protected boolean undecorated = false; + + private final void setScreen(ScreenImpl newScreen) { + if(screenReferenced) { + screenReferenced = false; + screen.removeReference(); + } + screen = newScreen; + } + + private boolean createNative() { + if( null==screen || 0!=windowHandle || !visible ) { + return 0 != windowHandle ; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() START ("+getThreadName()+", "+this+")"); + } + if( null != parentWindow && + NativeWindow.LOCK_SURFACE_NOT_READY >= parentWindow.lockSurface() ) { + throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow); + } + try { + if(validateParentWindowHandle()) { + if(!screenReferenced) { + screenReferenced = true; + screen.addReference(); + } + createNativeImpl(); + setVisibleImpl(true); + } + } finally { + if(null!=parentWindow) { + parentWindow.unlockSurface(); + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() END ("+getThreadName()+", "+this+")"); + } + return 0 != windowHandle ; + } + + private boolean validateParentWindowHandle() { + if(null!=parentWindow) { + parentWindowHandle = getNativeWindowHandle(parentWindow); + return 0 != parentWindowHandle ; + } + return true; + } + + private static long getNativeWindowHandle(NativeWindow nativeWindow) { + long handle = 0; + if(null!=nativeWindow) { + boolean locked=false; + try { + if( NativeWindow.LOCK_SURFACE_NOT_READY < nativeWindow.lockSurface() ) { + locked=true; + handle = nativeWindow.getWindowHandle(); + if(0==handle) { + throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+nativeWindow); + } + } + } catch (NativeWindowException nwe) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: not successful yet: "+nwe); + } + } finally { + if(locked) { + nativeWindow.unlockSurface(); + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: locked "+locked+", "+nativeWindow); + } + } + return handle; + } + + + //---------------------------------------------------------------------- + // NativeWindow: Native implementation + // + + protected int lockSurfaceImpl() { return LOCK_SUCCESS; } + + protected void unlockSurfaceImpl() { } + + //---------------------------------------------------------------------- + // Window: Native implementation + // + + protected abstract void createNativeImpl(); + + protected abstract void closeNativeImpl(); + + protected abstract void requestFocusImpl(boolean reparented); + + protected abstract void setVisibleImpl(boolean visible); + + protected abstract void setSizeImpl(int width, int height); + + protected abstract void setPositionImpl(int x, int y); + + protected abstract void reconfigureWindowImpl(int x, int y, int width, int height); + + protected void setTitleImpl(String title) {} + + //---------------------------------------------------------------------- + // NativeWindow + // + + public final int lockSurface() { + // We leave the ToolkitLock lock to the specializtion's discretion, + // ie the implicit JAWTWindow in case of AWTWindow + + // may throw RuntimeException if timed out while waiting for lock + windowLock.lock(); + + int res = lockSurfaceImpl(); + if(!isNativeValid()) { + windowLock.unlock(); + res = LOCK_SURFACE_NOT_READY; + } + return res; + } + + public final void unlockSurface() { + // may throw RuntimeException if not locked + windowLock.validateLocked(); + + unlockSurfaceImpl(); + + windowLock.unlock(); + // We leave the ToolkitLock unlock to the specializtion's discretion, + // ie the implicit JAWTWindow in case of AWTWindow + } + + public final boolean isSurfaceLockedByOtherThread() { + return windowLock.isLockedByOtherThread(); + } + + public final boolean isSurfaceLocked() { + return windowLock.isLocked(); + } + + public final Thread getSurfaceLockOwner() { + return windowLock.getOwner(); + } + + public final Exception getSurfaceLockStack() { + return windowLock.getLockedStack(); + } + + public final long getDisplayHandle() { + return getScreen().getDisplay().getHandle(); + } + + public final int getScreenIndex() { + return getScreen().getIndex(); + } + + public AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config; + } + + public final long getWindowHandle() { + return windowHandle; + } + + public long getSurfaceHandle() { + return windowHandle; // default: return window handle + } + + public boolean surfaceSwap() { + return false; + } + + //---------------------------------------------------------------------- + // Window + // + + public final boolean isNativeValid() { + return null != getScreen() && 0 != getWindowHandle() ; + } + + public final boolean isValid() { + return null != getScreen() ; + } + + public final NativeWindow getParentNativeWindow() { + return parentWindow; + } + + public final Screen getScreen() { + return screen; + } + + public void setVisible(boolean visible) { + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(this.parentWindowHandle)+", parentWindow "+(null!=this.parentWindow)/*+", "+this*/); + System.err.println(msg); + //Exception ee = new Exception(msg); + //ee.printStackTrace(); + } + if(isValid()) { + VisibleAction va = new VisibleAction(visible); + runOnEDTIfAvail(true, va); + if( va.getChanged() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + + } + } + + class VisibleAction implements Runnable { + boolean visible; + boolean nativeWindowCreated; + boolean madeVisible; + + public VisibleAction(boolean visible) { + this.visible = visible; + this.nativeWindowCreated = false; + this.madeVisible = false; + } + + public final boolean getNativeWindowCreated() { return nativeWindowCreated; } + public final boolean getBecameVisible() { return madeVisible; } + public final boolean getChanged() { return nativeWindowCreated || madeVisible; } + + public void run() { + windowLock.lock(); + try { + if( isValid() ) { + if(!visible && childWindows.size()>0) { + synchronized(childWindowsLock) { + for(Iterator i = childWindows.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).setVisible(false); + } + } + } + } + if(0==windowHandle && visible) { + WindowImpl.this.visible = visible; + if( 0<width*height ) { + nativeWindowCreated = createNative(); + } + } else if(WindowImpl.this.visible != visible) { + WindowImpl.this.visible = visible; + if(0 != windowHandle) { + setVisibleImpl(visible); + madeVisible = visible; + } + } + + if(null!=lifecycleHook) { + lifecycleHook.setVisibleAction(visible, nativeWindowCreated); + } + + if(0!=windowHandle && visible && childWindows.size()>0) { + synchronized(childWindowsLock) { + for(Iterator i = childWindows.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).setVisible(true); + } + } + } + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setVisible: END ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+WindowImpl.this.visible+", nativeWindowCreated: "+nativeWindowCreated+", madeVisible: "+madeVisible); + } + + } finally { + windowLock.unlock(); + } + getScreen().getDisplay().dispatchMessages(); // status up2date + } + } + + public void setSize(int width, int height) { + int visibleAction = 0; // 1 invisible, 2 visible + windowLock.lock(); + try{ + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setSize: START "+this.width+"x"+this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible); + System.err.println(msg); + // Exception e = new Exception(msg); + // e.printStackTrace(); + } + if (width != this.width || this.height != height) { + if(!fullscreen) { + nfs_width=width; + nfs_height=height; + if ( 0 != windowHandle && 0>=width*height && visible ) { + visibleAction=1; // invisible + this.width = 0; + this.height = 0; + } else if ( 0 == windowHandle && 0<width*height && visible ) { + visibleAction = 2; // visible + this.width = width; + this.height = height; + } else if ( 0 != windowHandle ) { + // this width/height will be set by windowChanged, called by the native implementation + setSizeImpl(width, height); + } else { + this.width = width; + this.height = height; + } + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: END "+this.width+"x"+this.height+", visibleAction "+visibleAction); + } + } finally { + windowLock.unlock(); + } + if(visibleAction>0) { + setVisible( ( 1 == visibleAction ) ? false : true ); + } + } + + public final void destroy() { + destroy(false); + } + + public void destroy(boolean unrecoverable) { + if(isValid()) { + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window.destroy(unrecoverable: "+unrecoverable+") START "+getThreadName()/*+", "+this*/); + System.err.println(msg); + //Exception ee = new Exception(msg); + //ee.printStackTrace(); + } + runOnEDTIfAvail(true, new DestroyAction(unrecoverable)); + } + } + + class DestroyAction implements Runnable { + boolean unrecoverable; + public DestroyAction(boolean unrecoverable) { + this.unrecoverable = unrecoverable; + } + public void run() { + windowLock.lock(); + try { + if( !isValid() ) { + return; // nop + } + + // Childs first .. + synchronized(childWindowsLock) { + // avoid ConcurrentModificationException: parent -> child -> parent.removeChild(this) + ArrayList clonedChildWindows = (ArrayList) childWindows.clone(); + while( clonedChildWindows.size() > 0 ) { + NativeWindow nw = (NativeWindow) clonedChildWindows.remove(0); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); + if(unrecoverable) { + ((WindowImpl)nw).destroy(unrecoverable); + } + } else { + nw.destroy(); + } + } + } + + if(null!=lifecycleHook) { + lifecycleHook.destroyAction(unrecoverable); + } + + // Now us .. + if(unrecoverable) { + if(null!=parentWindow && parentWindow instanceof Window) { + ((Window)parentWindow).removeChild(WindowImpl.this); + } + synchronized(childWindowsLock) { + childWindows = new ArrayList(); + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners = new ArrayList(); + } + windowListeners = new ArrayList(); + mouseListeners = new ArrayList(); + keyListeners = new ArrayList(); + } + if( null != screen && 0 != windowHandle ) { + closeNativeImpl(); + } + invalidate(unrecoverable); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") END "+getThreadName()/*+", "+WindowImpl.this*/); + } + } finally { + windowLock.unlock(); + } + } + } + + /** + * <p> + * render all native window information invalid, + * as if the native window was destroyed.<br></p> + * <p> + * all other resources and states are kept intact, + * ie listeners, parent handles and size, position etc.<br></p> + * + * @see #destroy() + * @see #destroy(boolean) + * @see #invalidate(boolean) + */ + public final void invalidate() { + invalidate(false); + } + + /** + * @param unrecoverable If true, all states, size, position, parent handles, + * reference to it's Screen are reset. + * Otherwise you can recreate the window, via <code>setVisible(true)</code>. + * @see #invalidate() + * @see #destroy() + * @see #destroy(boolean) + */ + protected void invalidate(boolean unrecoverable) { + windowLock.lock(); + try{ + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + String msg = new String("!!! Window Invalidate(unrecoverable: "+unrecoverable+") "+getThreadName()); + System.err.println(msg); + // Exception e = new Exception(msg); + // e.printStackTrace(); + } + windowHandle = 0; + visible = false; + fullscreen = false; + + if(unrecoverable) { + setScreen(null); + parentWindowHandle = 0; + parentWindow = null; + caps = null; + lifecycleHook = null; + + // Default position and dimension will be re-set immediately by user + width = 128; + height = 128; + x=0; + y=0; + } + } finally { + windowLock.unlock(); + } + } + + class ReparentActionImpl implements Runnable, ReparentAction { + NativeWindow newParentWindow; + boolean forceDestroyCreate; + int reparentAction; + + public ReparentActionImpl(NativeWindow newParentWindow, boolean forceDestroyCreate) { + this.newParentWindow = newParentWindow; + this.forceDestroyCreate = forceDestroyCreate; + this.reparentAction = -1; // ensure it's set + } + + public int getStrategy() { + return reparentAction; + } + + public void run() { + boolean wasVisible; + boolean displayChanged = false; + + windowLock.lock(); + try { + wasVisible = isVisible(); + + Window newParentWindowNEWT = null; + if(newParentWindow instanceof Window) { + newParentWindowNEWT = (Window) newParentWindow; + } + + long newParentWindowHandle = 0 ; + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: START ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCode(parentWindow)+", new parentWindow: "+Display.hashCode(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", DEBUG_TEST_REPARENT_INCOMPATIBLE "+DEBUG_TEST_REPARENT_INCOMPATIBLE); + } + + if(null!=newParentWindow) { + // Case: Child Window + newParentWindowHandle = getNativeWindowHandle(newParentWindow); + if(0 == newParentWindowHandle) { + // Case: Parent's native window not realized yet + if(null==newParentWindowNEWT) { + throw new NativeWindowException("Reparenting with non NEWT Window type only available after it's realized: "+newParentWindow); + } + // Destroy this window (handle screen + native) and use parent's Screen. + // It may be created properly when the parent is made visible. + destroy(false); + setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); + displayChanged = true; + reparentAction = ACTION_NATIVE_CREATION_PENDING; + } else if(newParentWindow != getParentNativeWindow()) { + // Case: Parent's native window realized and changed + if( !isNativeValid() ) { + // May create a new compatible Screen/Display and + // mark it for creation. + if(null!=newParentWindowNEWT) { + setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); + } else { + Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, getScreen()); + if( getScreen() != newScreen ) { + // auto destroy on-the-fly created Screen/Display + newScreen.setDestroyWhenUnused(true); + setScreen( (ScreenImpl) newScreen ); + displayChanged = true; + } + } + reparentAction = ACTION_NATIVE_CREATION; + } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate || + !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { + // Destroy this window (handle screen + native) and + // may create a new compatible Screen/Display and + // mark it for creation. + destroy(false); + if(null!=newParentWindowNEWT) { + setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); + } else { + setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, getScreen()) ); + screen.setDestroyWhenUnused(true); + } + displayChanged = true; + reparentAction = ACTION_NATIVE_CREATION; + } else { + // Mark it for native reparenting + reparentAction = ACTION_NATIVE_REPARENTING; + } + } else { + // Case: Parent's native window realized and not changed + reparentAction = ACTION_UNCHANGED; + } + } else { + // Case: Top Window + if( 0 == getParentWindowHandle() ) { + // Already Top Window + reparentAction = ACTION_UNCHANGED; + } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate ) { + // Destroy this window (handle screen + native) and + // keep Screen/Display and + // mark it for creation. + destroy(false); + reparentAction = ACTION_NATIVE_CREATION; + } else { + // Mark it for native reparenting + reparentAction = ACTION_NATIVE_REPARENTING; + } + } + parentWindowHandle = newParentWindowHandle; + + if ( ACTION_UNCHANGED > reparentAction ) { + throw new NativeWindowException("Internal Error: reparentAction not set"); + } + + if( ACTION_UNCHANGED == reparentAction ) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: NO CHANGE ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", visible "+wasVisible); + } + return; + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: ACTION ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", reparentAction "+reparentAction+", visible "+wasVisible); + } + + // rearrange window tree + if(null!=parentWindow && parentWindow instanceof Window) { + ((Window)parentWindow).removeChild(WindowImpl.this); + } + parentWindow = newParentWindow; + if(parentWindow instanceof Window) { + ((Window)parentWindow).addChild(WindowImpl.this); + } + + if( ACTION_NATIVE_CREATION_PENDING == reparentAction ) { + return; + } + + if( ACTION_NATIVE_REPARENTING == reparentAction ) { + NativeWindow parentWindowLocked = null; + if( null != parentWindow ) { + parentWindowLocked = parentWindow; + if(NativeWindow.LOCK_SURFACE_NOT_READY >= parentWindowLocked.lockSurface() ) { + throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow); + } + } + try { + if(0!=parentWindowHandle) { + // reset position to 0/0 within parent space + // FIXME .. cache position ? + x = 0; + y = 0; + } + DisplayImpl display = (DisplayImpl) screen.getDisplay(); + display.dispatchMessages(); // status up2date + if(wasVisible) { + visible = false; + setVisibleImpl(false); + display.dispatchMessages(); // status up2date + } + boolean ok = reparentWindowImpl(); + display.dispatchMessages(); // status up2date + if ( !ok ) { + // native reparent failed -> try creation + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: native reparenting failed ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentWindowHandle)+" - Trying recreation"); + } + destroy(false); + reparentAction = ACTION_NATIVE_CREATION ; + } if(wasVisible) { + visible = true; + setVisibleImpl(true); + requestFocusImpl(true); + display.dispatchMessages(); // status up2date + } + } finally { + if(null!=parentWindowLocked) { + parentWindowLocked.unlockSurface(); + } + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparentWindow: END ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCode(parentWindow)); + } + } finally { + windowLock.unlock(); + } + + if( ACTION_NATIVE_CREATION == reparentAction && wasVisible ) { + // This may run on the the Display/Screen connection, + // hence a new EDT task + runOnEDTIfAvail(true, reparentActionRecreate); + } + } + } + + class ReparentActionRecreate implements Runnable { + public void run() { + windowLock.lock(); + try { + visible = true; + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparentWindow: ReparentActionRecreate ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+Display.hashCode(parentWindow)); + } + setVisible(true); // native creation + requestFocus(); + } finally { + windowLock.unlock(); + } + } + } + private ReparentActionRecreate reparentActionRecreate = new ReparentActionRecreate(); + + public final int reparentWindow(NativeWindow newParent) { + return reparentWindow(newParent, false); + } + + public int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { + int reparentActionStrategy = ReparentAction.ACTION_INVALID; + if(isValid()) { + if(null!=lifecycleHook) { + lifecycleHook.reparentActionPre(); + } + try { + ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); + runOnEDTIfAvail(true, reparentAction); + reparentActionStrategy = reparentAction.getStrategy(); + if( isVisible() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + } finally { + if(null!=lifecycleHook) { + lifecycleHook.reparentActionPost(reparentActionStrategy); + } + } + } + return reparentActionStrategy; + } + + public final Capabilities getChosenCapabilities() { + return config.getNativeGraphicsConfiguration().getChosenCapabilities(); + } + + public final Capabilities getRequestedCapabilities() { + return (Capabilities)caps.clone(); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + if (title == null) { + title = ""; + } + this.title = title; + if(0 != getWindowHandle()) { + setTitleImpl(title); + } + } + + public void setUndecorated(boolean value) { + if(this.undecorated != value) { + undecorated = value; + if( 0 != windowHandle ) { + reconfigureWindowImpl(x, y, width, height); + requestFocus(); + } + } + } + + public boolean isUndecorated(boolean fullscreen) { + return 0 != getParentWindowHandle() || undecorated || fullscreen ; + } + + public boolean isUndecorated() { + return 0 != parentWindowHandle || undecorated || fullscreen ; + } + + public void requestFocus() { + enqueueRequestFocus(false); // FIXME: or shall we wait ? + } + + public Insets getInsets() { + return new Insets(0,0,0,0); + } + + public final int getWidth() { + return width; + } + + public final int getHeight() { + return height; + } + + public final int getX() { + return x; + } + + public final int getY() { + return y; + } + + public final boolean isVisible() { + return visible; + } + + public final boolean isFullscreen() { + return fullscreen; + } + + + //---------------------------------------------------------------------- + // Window + // + + /** + * If the implementation is capable of detecting a device change + * return true and clear the status/reason of the change. + */ + public boolean hasDeviceChanged() { + return false; + } + + public LifecycleHook getLifecycleHook() { + return lifecycleHook; + } + + public LifecycleHook setLifecycleHook(LifecycleHook hook) { + LifecycleHook old = lifecycleHook; + lifecycleHook = hook; + return old; + } + + /** If this Window actually wraps one from another toolkit such as + the AWT, this will return a non-null value. */ + public Object getWrappedWindow() { + return null; + } + + /** + * If set to true, the default value, this NEWT Window implementation will + * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.<br> + * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify()}. + */ + public void setHandleDestroyNotify(boolean b) { + handleDestroyNotify = b; + } + + //---------------------------------------------------------------------- + // WindowImpl + // + + protected final long getParentWindowHandle() { + return parentWindowHandle; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append(getClass().getName()+"[Config "+config+ + "\n, "+screen+ + "\n, ParentWindow "+parentWindow+ + "\n, ParentWindowHandle "+toHexString(parentWindowHandle)+ + "\n, WindowHandle "+toHexString(getWindowHandle())+ + "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ " (lockedExt "+isSurfaceLockedByOtherThread()+")"+ + "\n, Pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ + "\n, Visible "+isVisible()+ + "\n, Undecorated "+undecorated+ + "\n, Fullscreen "+fullscreen+ + "\n, WrappedWindow "+getWrappedWindow()+ + "\n, ChildWindows "+childWindows.size()); + + sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); + for (Iterator iter = surfaceUpdatedListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("], WindowListeners num "+windowListeners.size()+" ["); + for (Iterator iter = windowListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("], MouseListeners num "+mouseListeners.size()+" ["); + for (Iterator iter = mouseListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("], KeyListeners num "+keyListeners.size()+" ["); + for (Iterator iter = keyListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("] ]"); + return sb.toString(); + } + + protected final void setWindowHandle(long handle) { + windowHandle = handle; + } + + public void runOnEDTIfAvail(boolean wait, final Runnable task) { + Screen screen = getScreen(); + if(null==screen) { + throw new RuntimeException("Null screen of inner class: "+this); + } + DisplayImpl d = (DisplayImpl) screen.getDisplay(); + d.runOnEDTIfAvail(wait, task); + } + + class RequestFocusAction implements Runnable { + public void run() { + WindowImpl.this.requestFocusImpl(false); + } + } + RequestFocusAction requestFocusAction = new RequestFocusAction(); + + public void enqueueRequestFocus(boolean wait) { + runOnEDTIfAvail(wait, requestFocusAction); + } + + /** + * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. + * This allows notifying a covered window toolkit like AWT that the focus is requested, + * hence focus traversal can be made transparent. + */ + public void setFocusAction(FocusRunnable focusAction) { + focusAction = focusAction; + } + protected boolean focusAction() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.focusAction() START - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle())); + } + boolean res; + if(null!=focusAction) { + res = focusAction.run(); + } else { + res = false; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.focusAction() END - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle())+", res: "+res); + } + return res; + } + protected FocusRunnable focusAction = null; + + private boolean handleDestroyNotify = true; + + public void setPosition(int x, int y) { + windowLock.lock(); + try{ + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)); + } + if ( this.x != x || this.y != y ) { + if(!fullscreen) { + nfs_x=x; + nfs_y=y; + if(0!=windowHandle) { + // this x/y will be set by windowChanged, called by X11 + setPositionImpl(x, y); + } else { + this.x = x; + this.y = y; + } + } + } + } finally { + windowLock.unlock(); + } + } + + public boolean setFullscreen(boolean fullscreen) { + windowLock.lock(); + try{ + if(0!=windowHandle && this.fullscreen!=fullscreen) { + int x,y,w,h; + if(fullscreen) { + x = 0; y = 0; + w = screen.getWidth(); + h = screen.getHeight(); + } else { + if(0!=parentWindowHandle) { + x=0; + y=0; + } else { + x = nfs_x; + y = nfs_y; + } + w = nfs_width; + h = nfs_height; + } + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen); + } + this.fullscreen = fullscreen; + reconfigureWindowImpl(x, y, w, h); + requestFocus(); + } + } finally { + windowLock.unlock(); + } + if( isVisible() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + return this.fullscreen; + } + + //---------------------------------------------------------------------- + // Child Window Management + // + + private ArrayList childWindows = new ArrayList(); + private Object childWindowsLock = new Object(); + + public final void removeChild(NativeWindow win) { + synchronized(childWindowsLock) { + childWindows.remove(win); + } + } + + public final void addChild(NativeWindow win) { + if (win == null) { + return; + } + synchronized(childWindowsLock) { + childWindows.add(win); + } + } + + //---------------------------------------------------------------------- + // Generic Event Support + // + private void doEvent(boolean enqueue, boolean wait, com.jogamp.newt.event.NEWTEvent event) { + boolean done = false; + + if(!enqueue) { + done = consumeEvent(event); + wait = done; // don't wait if event can't be consumed now + } + + if(!done) { + enqueueEvent(wait, event); + } + } + + public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { + if(isValid()) { + ((DisplayImpl)getScreen().getDisplay()).enqueueEvent(wait, event); + } + } + + public boolean consumeEvent(NEWTEvent e) { + switch(e.getEventType()) { + // special repaint treatment + case WindowEvent.EVENT_WINDOW_REPAINT: + // queue repaint event in case surface is locked, ie in operation + if( isSurfaceLocked() ) { + // make sure only one repaint event is queued + if(!repaintQueued) { + repaintQueued=true; + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.consumeEvent: queued "+e); + // Exception ee = new Exception("Window.windowRepaint: "+e); + // ee.printStackTrace(); + } + return false; + } + return true; + } + repaintQueued=false; // no repaint event queued + break; + + // common treatment + case WindowEvent.EVENT_WINDOW_RESIZED: + // queue event in case surface is locked, ie in operation + if( isSurfaceLocked() ) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.consumeEvent: queued "+e); + // Exception ee = new Exception("Window.windowRepaint: "+e); + // ee.printStackTrace(); + } + return false; + } + break; + default: + break; + } + if(e instanceof WindowEvent) { + consumeWindowEvent((WindowEvent)e); + } else if(e instanceof KeyEvent) { + consumeKeyEvent((KeyEvent)e); + } else if(e instanceof MouseEvent) { + consumeMouseEvent((MouseEvent)e); + } else { + throw new NativeWindowException("Unexpected NEWTEvent type " + e); + } + return true; + } + protected boolean repaintQueued = false; + + // + // SurfaceUpdatedListener Support + // + + private ArrayList surfaceUpdatedListeners = new ArrayList(); + private Object surfaceUpdatedListenersLock = new Object(); + + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + addSurfaceUpdatedListener(-1, l); + } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size(); + } + surfaceUpdatedListeners.add(index, l); + } + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + if (l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners.remove(l); + } + } + + public void removeAllSurfaceUpdatedListener() { + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners = new ArrayList(); + } + } + + public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size()-1; + } + return (SurfaceUpdatedListener) surfaceUpdatedListeners.get(index); + } + } + + public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { + synchronized(surfaceUpdatedListenersLock) { + return (SurfaceUpdatedListener[]) surfaceUpdatedListeners.toArray(); + } + } + + public void surfaceUpdated(Object updater, NativeWindow window, long when) { + synchronized(surfaceUpdatedListenersLock) { + for(Iterator i = surfaceUpdatedListeners.iterator(); i.hasNext(); ) { + SurfaceUpdatedListener l = (SurfaceUpdatedListener) i.next(); + l.surfaceUpdated(updater, window, when); + } + } + } + + // + // MouseListener/Event Support + // + private ArrayList mouseListeners = new ArrayList(); + private int mouseButtonPressed = 0; // current pressed mouse button number + private long lastMousePressed = 0; // last time when a mouse button was pressed + private int lastMouseClickCount = 0; // last mouse button click count + public static final int ClickTimeout = 300; + + public void sendMouseEvent(int eventType, int modifiers, + int x, int y, int button, int rotation) { + doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation); + } + public void enqueueMouseEvent(boolean wait, int eventType, int modifiers, + int x, int y, int button, int rotation) { + doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation); + } + private void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, + int x, int y, int button, int rotation) { + if(x<0||y<0||x>=width||y>=height) { + return; // .. invalid .. + } + if(DEBUG_MOUSE_EVENT) { + System.err.println("doMouseEvent: enqueue"+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+ + ", mod "+modifiers+", pos "+x+"/"+y+", button "+button); + } + if(button<0||button>MouseEvent.BUTTON_NUMBER) { + throw new NativeWindowException("Invalid mouse button number" + button); + } + long when = System.currentTimeMillis(); + MouseEvent eClicked = null; + MouseEvent e = null; + + if(MouseEvent.EVENT_MOUSE_PRESSED==eventType) { + if(when-lastMousePressed<ClickTimeout) { + lastMouseClickCount++; + } else { + lastMouseClickCount=1; + } + lastMousePressed=when; + mouseButtonPressed=button; + e = new MouseEvent(eventType, this, when, + modifiers, x, y, lastMouseClickCount, button, 0); + } else if(MouseEvent.EVENT_MOUSE_RELEASED==eventType) { + e = new MouseEvent(eventType, this, when, + modifiers, x, y, lastMouseClickCount, button, 0); + if(when-lastMousePressed<ClickTimeout) { + eClicked = new MouseEvent(MouseEvent.EVENT_MOUSE_CLICKED, this, when, + modifiers, x, y, lastMouseClickCount, button, 0); + } else { + lastMouseClickCount=0; + lastMousePressed=0; + } + mouseButtonPressed=0; + } else if(MouseEvent.EVENT_MOUSE_MOVED==eventType) { + if (mouseButtonPressed>0) { + e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when, + modifiers, x, y, 1, mouseButtonPressed, 0); + } else { + e = new MouseEvent(eventType, this, when, + modifiers, x, y, 0, button, 0); + } + } else if(MouseEvent.EVENT_MOUSE_WHEEL_MOVED==eventType) { + e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, rotation); + } else { + e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, 0); + } + doEvent(enqueue, wait, e); + if(null!=eClicked) { + if(DEBUG_MOUSE_EVENT) { + System.err.println("doMouseEvent: synthesized MOUSE_CLICKED event"); + } + doEvent(enqueue, wait, eClicked); + } + } + + + public void addMouseListener(MouseListener l) { + addMouseListener(-1, l); + } + + public void addMouseListener(int index, MouseListener l) { + if(l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); + if(0>index) { + index = clonedListeners.size(); + } + clonedListeners.add(index, l); + mouseListeners = clonedListeners; + } + + public void removeMouseListener(MouseListener l) { + if (l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); + clonedListeners.remove(l); + mouseListeners = clonedListeners; + } + + public MouseListener getMouseListener(int index) { + ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); + if(0>index) { + index = clonedListeners.size()-1; + } + return (MouseListener) clonedListeners.get(index); + } + + public MouseListener[] getMouseListeners() { + return (MouseListener[]) mouseListeners.toArray(); + } + + protected void consumeMouseEvent(MouseEvent e) { + if(DEBUG_MOUSE_EVENT) { + System.err.println("consumeMouseEvent: event: "+e); + } + + for(Iterator i = mouseListeners.iterator(); i.hasNext(); ) { + MouseListener l = (MouseListener) i.next(); + switch(e.getEventType()) { + case MouseEvent.EVENT_MOUSE_CLICKED: + l.mouseClicked(e); + break; + case MouseEvent.EVENT_MOUSE_ENTERED: + l.mouseEntered(e); + break; + case MouseEvent.EVENT_MOUSE_EXITED: + l.mouseExited(e); + break; + case MouseEvent.EVENT_MOUSE_PRESSED: + l.mousePressed(e); + break; + case MouseEvent.EVENT_MOUSE_RELEASED: + l.mouseReleased(e); + break; + case MouseEvent.EVENT_MOUSE_MOVED: + l.mouseMoved(e); + break; + case MouseEvent.EVENT_MOUSE_DRAGGED: + l.mouseDragged(e); + break; + case MouseEvent.EVENT_MOUSE_WHEEL_MOVED: + l.mouseWheelMoved(e); + break; + default: + throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); + } + } + } + + // + // KeyListener/Event Support + // + + public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { + consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); + } + + public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { + enqueueEvent(wait, new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); + } + + public void addKeyListener(KeyListener l) { + addKeyListener(-1, l); + } + + public void addKeyListener(int index, KeyListener l) { + if(l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) keyListeners.clone(); + if(0>index) { + index = clonedListeners.size(); + } + clonedListeners.add(index, l); + keyListeners = clonedListeners; + } + + public void removeKeyListener(KeyListener l) { + if (l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) keyListeners.clone(); + clonedListeners.remove(l); + keyListeners = clonedListeners; + } + + public KeyListener getKeyListener(int index) { + ArrayList clonedListeners = (ArrayList) keyListeners.clone(); + if(0>index) { + index = clonedListeners.size()-1; + } + return (KeyListener) clonedListeners.get(index); + } + + public KeyListener[] getKeyListeners() { + return (KeyListener[]) keyListeners.toArray(); + } + + private ArrayList keyListeners = new ArrayList(); + + protected void consumeKeyEvent(KeyEvent e) { + if(DEBUG_KEY_EVENT) { + System.err.println("consumeKeyEvent: "+e); + } + for(Iterator i = keyListeners.iterator(); i.hasNext(); ) { + KeyListener l = (KeyListener) i.next(); + switch(e.getEventType()) { + case KeyEvent.EVENT_KEY_PRESSED: + l.keyPressed(e); + break; + case KeyEvent.EVENT_KEY_RELEASED: + l.keyReleased(e); + break; + case KeyEvent.EVENT_KEY_TYPED: + l.keyTyped(e); + break; + default: + throw new NativeWindowException("Unexpected key event type " + e.getEventType()); + } + } + } + + // + // WindowListener/Event Support + // + public void sendWindowEvent(int eventType) { + consumeWindowEvent( new WindowEvent(eventType, this, System.currentTimeMillis()) ); + } + + public void enqueueWindowEvent(boolean wait, int eventType) { + enqueueEvent( wait, new WindowEvent(eventType, this, System.currentTimeMillis()) ); + } + + private ArrayList windowListeners = new ArrayList(); + + public void addWindowListener(WindowListener l) { + addWindowListener(-1, l); + } + + public void addWindowListener(int index, WindowListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) windowListeners.clone(); + if(0>index) { + index = clonedListeners.size(); + } + clonedListeners.add(index, l); + windowListeners = clonedListeners; + } + + public final void removeWindowListener(WindowListener l) { + if (l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) windowListeners.clone(); + clonedListeners.remove(l); + windowListeners = clonedListeners; + } + + public WindowListener getWindowListener(int index) { + ArrayList clonedListeners = (ArrayList) windowListeners.clone(); + if(0>index) { + index = clonedListeners.size()-1; + } + return (WindowListener) clonedListeners.get(index); + } + + public WindowListener[] getWindowListeners() { + return (WindowListener[]) windowListeners.toArray(); + } + + protected void consumeWindowEvent(WindowEvent e) { + if(DEBUG_WINDOW_EVENT) { + System.err.println("consumeWindowEvent: "+e); + } + for(Iterator i = windowListeners.iterator(); i.hasNext(); ) { + WindowListener l = (WindowListener) i.next(); + switch(e.getEventType()) { + case WindowEvent.EVENT_WINDOW_RESIZED: + l.windowResized(e); + break; + case WindowEvent.EVENT_WINDOW_MOVED: + l.windowMoved(e); + break; + case WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY: + l.windowDestroyNotify(e); + break; + case WindowEvent.EVENT_WINDOW_GAINED_FOCUS: + l.windowGainedFocus(e); + break; + case WindowEvent.EVENT_WINDOW_LOST_FOCUS: + l.windowLostFocus(e); + break; + case WindowEvent.EVENT_WINDOW_REPAINT: + l.windowRepaint((WindowUpdateEvent)e); + break; + default: + throw + new NativeWindowException("Unexpected window event type " + + e.getEventType()); + } + } + } + + /** + * @param focusGained + */ + protected void focusChanged(boolean focusGained) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.focusChanged: ("+getThreadName()+"): "+focusGained+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + if (focusGained) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + } else { + sendWindowEvent(WindowEvent.EVENT_WINDOW_LOST_FOCUS); + } + } + + protected void visibleChanged(boolean visible) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + // Exception e = new Exception("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + // e.printStackTrace(); + } + this.visible = visible ; + } + + protected void sizeChanged(int newWidth, int newHeight) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.sizeChanged: ("+getThreadName()+"): "+width+"x"+height+" -> "+newWidth+"x"+newHeight+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + if(width != newWidth || height != newHeight) { + width = newWidth; + height = newHeight; + if(!fullscreen) { + nfs_width=width; + nfs_height=height; + } + if(isNativeValid()) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); + } + } + } + + protected void positionChanged(int newX, int newY) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.positionChanged: ("+getThreadName()+"): "+x+"/"+y+" -> "+newX+"/"+newY+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + if( 0==parentWindowHandle && ( x != newX || y != newY ) ) { + x = newX; + y = newY; + if(!fullscreen) { + nfs_x=x; + nfs_y=y; + } + sendWindowEvent(WindowEvent.EVENT_WINDOW_MOVED); + } + } + + protected void windowDestroyNotify() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowDestroyNotify START "+getThreadName()); + } + + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); + + if(handleDestroyNotify && isValid()) { + destroy(); + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowDestroyeNotify END "+getThreadName()); + } + } + + protected void windowDestroyed() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowDestroyed "+getThreadName()); + } + invalidate(); + } + + public void windowRepaint(int x, int y, int width, int height) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowRepaint "+getThreadName()+" - "+x+"/"+y+" "+width+"x"+height); + } + if(0>width) { + width=this.width; + } + if(0>height) { + height=this.height; + } + + NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(), + new Rectangle(x, y, width, height)); + if(isNativeValid()) { + doEvent(false, false, e); + } + } + + protected boolean reparentWindowImpl() { + // default implementation, no native reparenting support + return false; + } + + protected int getWindowLockRecursionCount() { + return windowLock.getRecursionCount(); + } + + // + // Reflection helper .. + // + + private static Class[] getCustomConstructorArgumentTypes(Class windowClass) { + Class[] argTypes = null; + try { + Method m = windowClass.getDeclaredMethod("getCustomConstructorArgumentTypes", new Class[] {}); + argTypes = (Class[]) m.invoke(null, null); + } catch (Throwable t) {} + return argTypes; + } + + private static int verifyConstructorArgumentTypes(Class[] types, Object[] args) { + if(types.length != args.length) { + return -1; + } + for(int i=0; i<args.length; i++) { + if(!types[i].isInstance(args[i])) { + return i; + } + } + return args.length; + } + + private static String getArgsStrList(Object[] args) { + StringBuffer sb = new StringBuffer(); + for(int i=0; i<args.length; i++) { + sb.append(args[i].getClass()); + if(i<args.length) { + sb.append(", "); + } + } + return sb.toString(); + } + + private static String getTypeStrList(Class[] types) { + StringBuffer sb = new StringBuffer(); + for(int i=0; i<types.length; i++) { + sb.append(types[i]); + if(i<types.length) { + sb.append(", "); + } + } + return sb.toString(); + } + + protected final void shouldNotCallThis() { + throw new NativeWindowException("Should not call this"); + } + + public static String getThreadName() { + return Display.getThreadName(); + } + + public static String toHexString(int hex) { + return Display.toHexString(hex); + } + + public static String toHexString(long hex) { + return Display.toHexString(hex); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java index 3290309bb..0199d6c72 100644 --- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java @@ -36,11 +36,12 @@ package com.jogamp.newt.impl.awt; import java.awt.event.*; import com.jogamp.newt.Display; import com.jogamp.newt.Window; +import com.jogamp.newt.impl.DisplayImpl; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; import java.util.*; -public class AWTDisplay extends Display { +public class AWTDisplay extends DisplayImpl { public AWTDisplay() { } diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java index eec83d721..eaf758b2d 100644 --- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java @@ -34,11 +34,12 @@ package com.jogamp.newt.impl.awt; import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; import java.awt.DisplayMode; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; -public class AWTScreen extends Screen { +public class AWTScreen extends ScreenImpl { public AWTScreen() { } diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java index 9da1eb860..e4452d2c8 100644 --- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java @@ -50,6 +50,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.*; import com.jogamp.newt.Window; +import com.jogamp.newt.impl.WindowImpl; import java.awt.Insets; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; @@ -58,7 +59,7 @@ import javax.media.nativewindow.awt.*; AWT. This is provided for convenience of porting to platforms supporting Java SE. */ -public class AWTWindow extends Window { +public class AWTWindow extends WindowImpl { public AWTWindow() { this(null); @@ -84,7 +85,7 @@ public class AWTWindow extends Window { // non fullscreen dimensions .. private int nfs_width, nfs_height, nfs_x, nfs_y; - protected void requestFocusImpl() { + protected void requestFocusImpl(boolean reparented) { runOnEDT(true, new Runnable() { public void run() { container.requestFocus(); @@ -104,7 +105,7 @@ public class AWTWindow extends Window { protected void createNativeImpl() { - if(0!=parentWindowHandle) { + if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead"); } @@ -145,11 +146,11 @@ public class AWTWindow extends Window { } } }); - this.windowHandle = 1; // just a marker .. + setWindowHandle(1); // just a marker .. } protected void closeNativeImpl() { - this.windowHandle = 0; // just a marker .. + setWindowHandle(0); // just a marker .. if(null!=container) { runOnEDT(true, new Runnable() { public void run() { @@ -207,7 +208,7 @@ public class AWTWindow extends Window { DisplayMode mode = ((AWTGraphicsDevice)config.getScreen().getDevice()).getGraphicsDevice().getDisplayMode(); int w = mode.getWidth(); int h = mode.getHeight(); - ((AWTScreen)screen).setScreenSize(w, h); + ((AWTScreen)getScreen()).setScreenSize(w, h); } protected void setSizeImpl(final int width, final int height) { @@ -248,7 +249,7 @@ public class AWTWindow extends Window { } } - protected void setFullscreenImpl(final boolean fullscreen, final int x, final int y, final int w, final int h) { + protected void reconfigureWindowImpl(final int x, final int y, final int width, final int height) { /** An AWT event on setSize() would bring us in a deadlock situation, hence invokeLater() */ runOnEDT(false, new Runnable() { public void run() { @@ -262,7 +263,7 @@ public class AWTWindow extends Window { } } container.setLocation(x, y); - container.setSize(w, h); + container.setSize(width, height); } }); } @@ -272,7 +273,7 @@ public class AWTWindow extends Window { } private void runOnEDT(boolean wait, Runnable r) { - EDTUtil edtUtil = screen.getDisplay().getEDTUtil(); + EDTUtil edtUtil = getScreen().getDisplay().getEDTUtil(); if ( ( null != edtUtil && edtUtil.isCurrentThreadEDT() ) || EventQueue.isDispatchThread() ) { r.run(); } else { diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java index c8e69dac6..0bd4c3b5d 100644 --- a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java @@ -36,7 +36,7 @@ package com.jogamp.newt.impl.intel.gdl; import com.jogamp.newt.impl.*; import javax.media.nativewindow.*; -public class Display extends com.jogamp.newt.Display { +public class Display extends com.jogamp.newt.impl.DisplayImpl { static int initCounter = 0; static { diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java index 3aded5df3..c5253e142 100644 --- a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java @@ -36,7 +36,7 @@ package com.jogamp.newt.impl.intel.gdl; import com.jogamp.newt.impl.*; import javax.media.nativewindow.*; -public class Screen extends com.jogamp.newt.Screen { +public class Screen extends com.jogamp.newt.impl.ScreenImpl { static { Display.initSingleton(); diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java index 5f40a35ae..040fa15a9 100644 --- a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java @@ -35,7 +35,7 @@ package com.jogamp.newt.impl.intel.gdl; import javax.media.nativewindow.*; -public class Window extends com.jogamp.newt.Window { +public class Window extends com.jogamp.newt.impl.WindowImpl { static { Display.initSingleton(); } @@ -46,11 +46,11 @@ public class Window extends com.jogamp.newt.Window { static long nextWindowHandle = 1; protected void createNativeImpl() { - if(0!=parentWindowHandle) { + if(0!=getParentWindowHandle()) { throw new NativeWindowException("GDL Window does not support window parenting"); } - AbstractGraphicsScreen aScreen = screen.getGraphicsScreen(); - AbstractGraphicsDevice aDevice = screen.getDisplay().getGraphicsDevice(); + AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); + AbstractGraphicsDevice aDevice = getScreen().getDisplay().getGraphicsDevice(); config = GraphicsConfigurationFactory.getFactory(aDevice).chooseGraphicsConfiguration(caps, null, aScreen); if (config == null) { @@ -58,9 +58,9 @@ public class Window extends com.jogamp.newt.Window { } synchronized(Window.class) { - windowHandle = nextWindowHandle++; + setWindowHandle(nextWindowHandle++); // just a marker - surfaceHandle = CreateSurface(aDevice.getHandle(), screen.getWidth(), screen.getHeight(), x, y, width, height); + surfaceHandle = CreateSurface(aDevice.getHandle(), getScreen().getWidth(), getScreen().getHeight(), x, y, width, height); if (surfaceHandle == 0) { throw new NativeWindowException("Error creating window"); } @@ -73,13 +73,13 @@ public class Window extends com.jogamp.newt.Window { CloseSurface(getDisplayHandle(), surfaceHandle); } surfaceHandle = 0; - ((Display)screen.getDisplay()).setFocus(null); + ((Display)getScreen().getDisplay()).setFocus(null); } } protected void setVisibleImpl(boolean visible) { if(visible) { - ((Display)screen.getDisplay()).setFocus(this); + ((Display)getScreen().getDisplay()).setFocus(this); } } @@ -109,17 +109,17 @@ public class Window extends com.jogamp.newt.Window { } } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + protected void reconfigureWindowImpl(int x, int y, int width, int height) { if(0!=surfaceHandle) { - SetBounds0(surfaceHandle, screen.getWidth(), screen.getHeight(), x, y, w, h); + SetBounds0(surfaceHandle, getScreen().getWidth(), getScreen().getHeight(), x, y, width, height); } } - protected void requestFocusImpl() { - ((Display)screen.getDisplay()).setFocus(this); + protected void requestFocusImpl(boolean reparented) { + ((Display)getScreen().getDisplay()).setFocus(this); } - public long getSurfaceHandle() { + public final long getSurfaceHandle() { return surfaceHandle; } diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java index 9b8689114..42cdb9ca3 100644 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java @@ -41,7 +41,7 @@ import com.jogamp.newt.impl.*; import com.jogamp.newt.util.EDTUtil; import com.jogamp.newt.util.MainThread; -public class MacDisplay extends Display { +public class MacDisplay extends DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java index 317a3161c..21018b2be 100644 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java @@ -34,9 +34,10 @@ package com.jogamp.newt.impl.macosx; import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; import javax.media.nativewindow.*; -public class MacScreen extends Screen { +public class MacScreen extends ScreenImpl { static { MacDisplay.initSingleton(); } diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java index 7571c05be..6432f363e 100644 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java @@ -41,7 +41,7 @@ import com.jogamp.newt.event.*; import com.jogamp.newt.impl.*; import com.jogamp.newt.util.*; -public class MacWindow extends Window { +public class MacWindow extends WindowImpl { // Window styles private static final int NSBorderlessWindowMask = 0; @@ -153,8 +153,8 @@ public class MacWindow extends Window { nsViewLock.lock(); try { if(DEBUG_IMPLEMENTATION) { System.out.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } - if (windowHandle != 0) { - close0(windowHandle); + if (getWindowHandle() != 0) { + close0(getWindowHandle()); } } catch (Throwable t) { if(DEBUG_IMPLEMENTATION) { @@ -162,28 +162,14 @@ public class MacWindow extends Window { e.printStackTrace(); } } finally { - windowHandle = 0; + setWindowHandle(0); nsViewLock.unlock(); } windowDestroyed(); // No OSX hook for DidClose, so do it here } - public long getWindowHandle() { - nsViewLock.lock(); - try { - return windowHandle; - } finally { - nsViewLock.unlock(); - } - } - - public long getSurfaceHandle() { - nsViewLock.lock(); - try { - return surfaceHandle; - } finally { - nsViewLock.unlock(); - } + public final long getSurfaceHandle() { + return surfaceHandle; } public Insets getInsets() { @@ -200,18 +186,12 @@ public class MacWindow extends Window { private RecursiveToolkitLock nsViewLock = new RecursiveToolkitLock(); - public synchronized int lockSurface() throws NativeWindowException { + protected int lockSurfaceImpl() { nsViewLock.lock(); - try { - return super.lockSurface(); - } catch (RuntimeException re) { - nsViewLock.unlock(); - throw re; - } + return LOCK_SUCCESS; } - public void unlockSurface() { - super.unlockSurface(); + protected void unlockSurfaceImpl() { nsViewLock.unlock(); } @@ -220,12 +200,12 @@ public class MacWindow extends Window { try { if (visible) { createWindow(false, getX(), getY(), getWidth(), getHeight(), isFullscreen()); - if (windowHandle != 0) { - makeKeyAndOrderFront0(windowHandle); + if (getWindowHandle() != 0) { + makeKeyAndOrderFront0(getWindowHandle()); } } else { - if (windowHandle != 0) { - orderOut0(windowHandle); + if (getWindowHandle() != 0) { + orderOut0(getWindowHandle()); } } } finally { @@ -237,21 +217,17 @@ public class MacWindow extends Window { // FIXME: move nsViewLock up to window lock nsViewLock.lock(); try { - if (windowHandle != 0) { - setTitle0(windowHandle, title); - } + setTitle0(getWindowHandle(), title); } finally { nsViewLock.unlock(); } } - protected void requestFocusImpl() { + protected void requestFocusImpl(boolean reparented) { // FIXME: move nsViewLock up to window lock nsViewLock.lock(); try { - if (windowHandle != 0) { - makeKey0(windowHandle); - } + makeKey0(getWindowHandle()); } finally { nsViewLock.unlock(); } @@ -261,9 +237,7 @@ public class MacWindow extends Window { // this width/height will be set by sizeChanged, called by OSX nsViewLock.lock(); try { - if (windowHandle != 0) { - setContentSize0(windowHandle, width, height); - } + setContentSize0(getWindowHandle(), width, height); } finally { nsViewLock.unlock(); } @@ -273,23 +247,21 @@ public class MacWindow extends Window { // this x/y will be set by positionChanged, called by OSX nsViewLock.lock(); try { - if (windowHandle != 0) { - setFrameTopLeftPoint0(parentWindowHandle, windowHandle, x, y); - } + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), x, y); } finally { nsViewLock.unlock(); } } - protected void setFullscreenImpl(final boolean fullscreen, final int x, final int y, final int w, final int h) { + protected void reconfigureWindowImpl(int x, int y, int width, int height) { nsViewLock.lock(); try { if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("MacWindow fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h); + System.err.println("MacWindow reconfig: "+fullscreen+" "+x+"/"+y+" "+width+"x"+height); } - createWindow(true, x, y, w, h, fullscreen); - if (windowHandle != 0) { - makeKeyAndOrderFront0(windowHandle); + createWindow(true, x, y, width, height, fullscreen); + if (getWindowHandle() != 0) { + makeKeyAndOrderFront0(getWindowHandle()); } } finally { nsViewLock.unlock(); @@ -402,36 +374,36 @@ public class MacWindow extends Window { private void createWindow(final boolean recreate, final int x, final int y, final int width, final int height, final boolean fullscreen) { - if(0!=windowHandle && !recreate) { + if(0!=getWindowHandle() && !recreate) { return; } try { //runOnEDTIfAvail(true, new Runnable() { // public void run() { - if(0!=windowHandle) { + if(0!=getWindowHandle()) { // save the view .. close the window - surfaceHandle = changeContentView0(parentWindowHandle, windowHandle, 0); + surfaceHandle = changeContentView0(getParentWindowHandle(), getWindowHandle(), 0); if(recreate && 0==surfaceHandle) { throw new NativeWindowException("Internal Error - recreate, window but no view"); } - close0(windowHandle); - windowHandle=0; + close0(getWindowHandle()); + setWindowHandle(0); } else { surfaceHandle = 0; } - windowHandle = createWindow0(parentWindowHandle, + setWindowHandle(createWindow0(getParentWindowHandle(), x, y, width, height, fullscreen, (isUndecorated(fullscreen) ? NSBorderlessWindowMask : NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), NSBackingStoreBuffered, - getScreen().getIndex(), surfaceHandle); - if (windowHandle == 0) { + getScreen().getIndex(), surfaceHandle)); + if (getWindowHandle() == 0) { throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); } - surfaceHandle = contentView0(windowHandle); - setTitle0(windowHandle, getTitle()); + surfaceHandle = contentView0(getWindowHandle()); + setTitle0(getWindowHandle(), getTitle()); // don't make the window visible on window creation // makeKeyAndOrderFront0(windowHandle); // } } ); diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java index 8b8ce1f41..18d058a9c 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java @@ -38,7 +38,7 @@ import com.jogamp.opengl.impl.egl.*; import javax.media.nativewindow.*; import javax.media.nativewindow.egl.*; -public class Display extends com.jogamp.newt.Display { +public class Display extends com.jogamp.newt.impl.DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java index f38e7b4dc..50fdf92e5 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java @@ -35,7 +35,7 @@ package com.jogamp.newt.impl.opengl.broadcom.egl; import javax.media.nativewindow.*; -public class Screen extends com.jogamp.newt.Screen { +public class Screen extends com.jogamp.newt.impl.ScreenImpl { static { Display.initSingleton(); diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java index d6b802a85..947e28c27 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java @@ -38,7 +38,7 @@ import javax.media.nativewindow.*; import javax.media.opengl.GLCapabilities; import javax.media.nativewindow.NativeWindowException; -public class Window extends com.jogamp.newt.Window { +public class Window extends com.jogamp.newt.impl.WindowImpl { static { Display.initSingleton(); } @@ -47,7 +47,7 @@ public class Window extends com.jogamp.newt.Window { } protected void createNativeImpl() { - if(0!=parentWindowHandle) { + if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported (yet)"); } // query a good configuration .. even thought we drop this one @@ -58,8 +58,8 @@ public class Window extends com.jogamp.newt.Window { } setSizeImpl(getScreen().getWidth(), getScreen().getHeight()); - windowHandle = realizeWindow(true, width, height); - if (0 == windowHandle) { + setWindowHandle(realizeWindow(true, width, height)); + if (0 == getWindowHandle()) { throw new NativeWindowException("Error native Window Handle is null"); } } @@ -72,8 +72,10 @@ public class Window extends com.jogamp.newt.Window { protected void setVisibleImpl(boolean visible) { } + protected void requestFocusImpl(boolean reparented) { } + protected void setSizeImpl(int width, int height) { - if(0!=windowHandle) { + if(0!=getWindowHandle()) { // n/a in BroadcomEGL System.err.println("BCEGL Window.setSizeImpl n/a in BroadcomEGL with realized window"); } else { @@ -87,17 +89,14 @@ public class Window extends com.jogamp.newt.Window { System.err.println("BCEGL Window.setPositionImpl n/a in BroadcomEGL"); } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { + protected void reconfigureWindowImpl(int x, int y, int width, int height) { // n/a in BroadcomEGL System.err.println("setFullscreen n/a in BroadcomEGL"); } public boolean surfaceSwap() { - if ( 0!=windowHandle ) { - SwapWindow(getDisplayHandle(), windowHandle); - return true; - } - return false; + SwapWindow(getDisplayHandle(), getWindowHandle()); + return true; } //---------------------------------------------------------------------- @@ -126,7 +125,7 @@ public class Window extends com.jogamp.newt.Window { this.width = width; this.height = height; GLCapabilities capsReq = (GLCapabilities) config.getRequestedCapabilities(); - config = EGLGraphicsConfiguration.create(capsReq, screen.getGraphicsScreen(), cfgID); + config = EGLGraphicsConfiguration.create(capsReq, getScreen().getGraphicsScreen(), cfgID); if (config == null) { throw new NativeWindowException("Error creating EGLGraphicsConfiguration from id: "+cfgID+", "+this); } diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java index 1845342a0..eab1816da 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java @@ -39,7 +39,7 @@ import com.jogamp.opengl.impl.egl.*; import javax.media.nativewindow.*; import javax.media.nativewindow.egl.*; -public class KDDisplay extends Display { +public class KDDisplay extends DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java index c7db047f6..a814f15b5 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java @@ -34,9 +34,10 @@ package com.jogamp.newt.impl.opengl.kd; import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; import javax.media.nativewindow.*; -public class KDScreen extends Screen { +public class KDScreen extends ScreenImpl { static { KDDisplay.initSingleton(); } diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java index 43e4ac021..6930741b8 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java @@ -42,7 +42,7 @@ import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLProfile; import javax.media.nativewindow.NativeWindowException; -public class KDWindow extends Window { +public class KDWindow extends WindowImpl { private static final String WINDOW_CLASS_NAME = "NewtWindow"; // non fullscreen dimensions .. private int nfs_width, nfs_height, nfs_x, nfs_y; @@ -55,7 +55,7 @@ public class KDWindow extends Window { } protected void createNativeImpl() { - if(0!=parentWindowHandle) { + if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported (yet)"); } config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration(caps, null, getScreen().getGraphicsScreen()); @@ -71,8 +71,8 @@ public class KDWindow extends Window { throw new NativeWindowException("Error creating egl window: "+config); } setVisible0(eglWindowHandle, false); - windowHandle = RealizeWindow(eglWindowHandle); - if (0 == windowHandle) { + setWindowHandle(RealizeWindow(eglWindowHandle)); + if (0 == getWindowHandle()) { throw new NativeWindowException("Error native Window Handle is null"); } windowHandleClose = eglWindowHandle; @@ -89,6 +89,8 @@ public class KDWindow extends Window { setVisible0(eglWindowHandle, visible); } + protected void requestFocusImpl(boolean reparented) { } + protected void setSizeImpl(int width, int height) { if(0!=eglWindowHandle) { setSize0(eglWindowHandle, width, height); @@ -100,11 +102,11 @@ public class KDWindow extends Window { System.err.println("setPosition n/a in KD"); } - protected void setFullscreenImpl(final boolean fullscreen, final int x, final int y, final int w, final int h) { + protected void reconfigureWindowImpl(int x, int y, int width, int height) { if(0!=eglWindowHandle) { setFullScreen0(eglWindowHandle, fullscreen); if(!fullscreen) { - setSize0(eglWindowHandle, w, h); + setSize0(eglWindowHandle, width, height); } } } @@ -127,7 +129,7 @@ public class KDWindow extends Window { protected void sizeChanged(int newWidth, int newHeight) { if(fullscreen) { - ((KDScreen)screen).setScreenSize(width, height); + ((KDScreen)getScreen()).setScreenSize(width, height); } super.sizeChanged(newWidth, newHeight); } diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java index cfc35e1f8..fe86257ff 100644 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java @@ -38,7 +38,7 @@ import javax.media.nativewindow.windows.*; import com.jogamp.newt.*; import com.jogamp.newt.impl.*; -public class WindowsDisplay extends Display { +public class WindowsDisplay extends DisplayImpl { protected static final String WINDOW_CLASS_NAME = "NewtWindowClass"; private static int windowClassAtom; diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java index 2197667cd..5dd2689e5 100644 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java @@ -34,9 +34,10 @@ package com.jogamp.newt.impl.windows; import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; import javax.media.nativewindow.*; -public class WindowsScreen extends Screen { +public class WindowsScreen extends ScreenImpl { static { WindowsDisplay.initSingleton(); } diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java index 15d9ac8b0..ee3c8e197 100644 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java @@ -35,16 +35,14 @@ package com.jogamp.newt.impl.windows; import javax.media.nativewindow.*; import com.jogamp.newt.*; -import com.jogamp.newt.event.*; import com.jogamp.newt.util.*; +import com.jogamp.newt.impl.WindowImpl; -public class WindowsWindow extends Window { +public class WindowsWindow extends WindowImpl { private long hmon; private long hdc; private long windowHandleClose; - // non fullscreen dimensions .. - private int nfs_width, nfs_height, nfs_x, nfs_y; private final Insets insets = new Insets(0, 0, 0, 0); static { @@ -54,32 +52,28 @@ public class WindowsWindow extends Window { public WindowsWindow() { } - public int lockSurface() throws NativeWindowException { - int res = super.lockSurface(); - if( LOCK_SUCCESS == res && 0 != windowHandle && 0 == hdc ) { - hdc = GetDC0(windowHandle); - hmon = MonitorFromWindow0(windowHandle); + protected int lockSurfaceImpl() { + if( 0 != getWindowHandle() && 0 == hdc ) { + hdc = GetDC0(getWindowHandle()); + hmon = MonitorFromWindow0(getWindowHandle()); } - return res; + return LOCK_SUCCESS; } - public void unlockSurface() { - getWindowLock().validateLocked(); - - if ( 0 != hdc && 0 != windowHandle && getWindowLock().getRecursionCount() == 0) { - ReleaseDC0(windowHandle, hdc); + protected void unlockSurfaceImpl() { + if ( 0 != hdc && 0 != getWindowHandle() && getWindowLockRecursionCount() == 0) { + ReleaseDC0(getWindowHandle(), hdc); hdc=0; } - super.unlockSurface(); } - public long getSurfaceHandle() { + public final long getSurfaceHandle() { return hdc; } public boolean hasDeviceChanged() { - if(0!=windowHandle) { - long _hmon = MonitorFromWindow0(windowHandle); + if(0!=getWindowHandle()) { + long _hmon = MonitorFromWindow0(getWindowHandle()); if (hmon != _hmon) { if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { Exception e = new Exception("!!! Window Device Changed "+Thread.currentThread().getName()+ @@ -100,17 +94,17 @@ public class WindowsWindow extends Window { if (config == null) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } - windowHandle = CreateWindow0(parentWindowHandle, + setWindowHandle(CreateWindow0(getParentWindowHandle(), display.getWindowClassAtom(), display.WINDOW_CLASS_NAME, display.getHInstance(), - 0, undecorated, x, y, width, height); - if (windowHandle == 0) { + 0, undecorated, x, y, width, height)); + if (getWindowHandle() == 0) { throw new NativeWindowException("Error creating window"); } - windowHandleClose = windowHandle; + windowHandleClose = getWindowHandle(); if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { Exception e = new Exception("!!! Window new window handle "+Thread.currentThread().getName()+ - " (Parent HWND "+toHexString(parentWindowHandle)+ - ") : HWND "+toHexString(windowHandle)+", "+Thread.currentThread()); + " (Parent HWND "+toHexString(getParentWindowHandle())+ + ") : HWND "+toHexString(getWindowHandle())+", "+Thread.currentThread()); e.printStackTrace(); } } @@ -149,38 +143,34 @@ public class WindowsWindow extends Window { } protected void setVisibleImpl(boolean visible) { - setVisible0(windowHandle, visible); + setVisible0(getWindowHandle(), visible); } protected void setSizeImpl(int width, int height) { // this width/height will be set by sizeChanged, called by Windows - setSize0(parentWindowHandle, windowHandle, x, y, width, height); + setSize0(getParentWindowHandle(), getWindowHandle(), x, y, width, height); } protected void setPositionImpl(int x, int y) { // this x/y will be set by positionChanged, called by Windows - setPosition0(parentWindowHandle, windowHandle, x , y /*, width, height*/); + setPosition0(getParentWindowHandle(), getWindowHandle(), x , y /*, width, height*/); } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { - setFullscreen0(fullscreen?0:parentWindowHandle, windowHandle, x, y, w, h, isUndecorated(fullscreen)); + protected void reconfigureWindowImpl(int x, int y, int width, int height) { + reconfigureWindow0(fullscreen?0:getParentWindowHandle(), getWindowHandle(), x, y, width, height, isUndecorated(fullscreen)); } protected boolean reparentWindowImpl() { - if(0!=windowHandle) { - reparentWindow0(fullscreen?0:parentWindowHandle, windowHandle, x, y, width, height, isUndecorated()); - } + reparentWindow0(fullscreen?0:getParentWindowHandle(), getWindowHandle(), x, y, width, height, isUndecorated()); return true; } - protected void requestFocusImpl() { - if (windowHandle != 0L) { - requestFocus0(windowHandle); - } + protected void requestFocusImpl(boolean reparented) { + requestFocus0(getWindowHandle(), reparented); } protected void setTitleImpl(final String title) { - setTitle0(windowHandle, title); + setTitle0(getWindowHandle(), title); } public Insets getInsets() { @@ -203,10 +193,11 @@ public class WindowsWindow extends Window { private static native void setVisible0(long windowHandle, boolean visible); private native void setSize0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height); private static native void setPosition0(long parentWindowHandle, long windowHandle, int x, int y /*, int width, int height*/); - private native void setFullscreen0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, boolean isUndecorated); + private native void reconfigureWindow0(long parentWindowHandle, long windowHandle, + int x, int y, int width, int height, boolean isUndecorated); private native void reparentWindow0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, boolean isUndecorated); private static native void setTitle0(long windowHandle, String title); - private native void requestFocus0(long windowHandle); + private native void requestFocus0(long windowHandle, boolean reparented); private void insetsChanged(int left, int top, int right, int bottom) { if (left != -1 && top != -1 && right != -1 && bottom != -1) { diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java index 22b5e8470..f96625d8e 100644 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java @@ -39,7 +39,7 @@ import com.jogamp.newt.*; import com.jogamp.newt.impl.*; import com.jogamp.nativewindow.impl.x11.X11Util; -public class X11Display extends Display { +public class X11Display extends DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java index aa53ea5d0..9d4c592c8 100644 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java @@ -34,9 +34,10 @@ package com.jogamp.newt.impl.x11; import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; import javax.media.nativewindow.x11.*; -public class X11Screen extends Screen { +public class X11Screen extends ScreenImpl { static { X11Display.initSingleton(); diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java index 894de9ae5..f9fce6fc1 100644 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java @@ -35,10 +35,11 @@ package com.jogamp.newt.impl.x11; import com.jogamp.newt.*; import com.jogamp.newt.event.*; +import com.jogamp.newt.impl.WindowImpl; import javax.media.nativewindow.*; import javax.media.nativewindow.x11.*; -public class X11Window extends Window { +public class X11Window extends WindowImpl { private static final String WINDOW_CLASS_NAME = "NewtWindow"; static { @@ -57,14 +58,14 @@ public class X11Window extends Window { } X11GraphicsConfiguration x11config = (X11GraphicsConfiguration) config; long visualID = x11config.getVisualID(); - long w = CreateWindow0(parentWindowHandle, + long w = CreateWindow0(getParentWindowHandle(), display.getHandle(), screen.getIndex(), visualID, display.getJavaObjectAtom(), display.getWindowDeleteAtom(), x, y, width, height, isUndecorated()); - if (w == 0 || w!=windowHandle) { + if (w == 0 || w!=getWindowHandle()) { throw new NativeWindowException("Error creating window: "+w); } - windowHandleClose = windowHandle; + windowHandleClose = getWindowHandle(); } protected void closeNativeImpl() { @@ -90,42 +91,39 @@ public class X11Window extends Window { } protected void setVisibleImpl(boolean visible) { - setVisible0(getDisplayHandle(), windowHandle, visible); + setVisible0(getDisplayHandle(), getWindowHandle(), visible); } protected void setSizeImpl(int width, int height) { // this width/height will be set by windowChanged, called by X11 - setSize0(getDisplayHandle(), windowHandle, width, height); + setSize0(getDisplayHandle(), getWindowHandle(), width, height); } protected void setPositionImpl(int x, int y) { - setPosition0(parentWindowHandle, getDisplayHandle(), windowHandle, x, y); + setPosition0(getParentWindowHandle(), getDisplayHandle(), getWindowHandle(), x, y); } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { - setPosSizeDecor0(fullscreen?0:parentWindowHandle, getDisplayHandle(), getScreenIndex(), windowHandle, - x, y, w, h, isUndecorated(fullscreen), isVisible()); + protected void reconfigureWindowImpl(int x, int y, int width, int height) { + reconfigureWindow0(fullscreen?0:getParentWindowHandle(), getDisplayHandle(), getScreenIndex(), getWindowHandle(), + x, y, width, height, isUndecorated(fullscreen), isVisible()); } protected boolean reparentWindowImpl() { - if(0!=windowHandle) { - reparentWindow0(fullscreen?0:parentWindowHandle, getDisplayHandle(), getScreenIndex(), windowHandle, + if(0!=getWindowHandle()) { + reparentWindow0(fullscreen?0:getParentWindowHandle(), getDisplayHandle(), getScreenIndex(), getWindowHandle(), x, y, isUndecorated(), isVisible()); } return true; } - protected void requestFocusImpl() { - if (windowHandle != 0L) { - requestFocus0(getDisplayHandle(), windowHandle); - } + protected void requestFocusImpl(boolean reparented) { + requestFocus0(getDisplayHandle(), getWindowHandle(), reparented); } protected void setTitleImpl(String title) { - setTitle0(getDisplayHandle(), windowHandle, title); + setTitle0(getDisplayHandle(), getWindowHandle(), title); } - //---------------------------------------------------------------------- // Internals only // @@ -137,16 +135,16 @@ public class X11Window extends Window { private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom); private native void setVisible0(long display, long windowHandle, boolean visible); private native void setSize0(long display, long windowHandle, int width, int height); - private native void setPosSizeDecor0(long parentWindowHandle, long display, int screen_index, long windowHandle, - int x, int y, int width, int height, boolean undecorated, boolean isVisible); + private native void reconfigureWindow0(long parentWindowHandle, long display, int screen_index, long windowHandle, + int x, int y, int width, int height, boolean undecorated, boolean isVisible); private native void setTitle0(long display, long windowHandle, String title); - private native void requestFocus0(long display, long windowHandle); + private native void requestFocus0(long display, long windowHandle, boolean reparented); private native void setPosition0(long parentWindowHandle, long display, long windowHandle, int x, int y); private native void reparentWindow0(long parentWindowHandle, long display, int screen_index, long windowHandle, int x, int y, boolean undecorated, boolean isVisible); private void windowCreated(long windowHandle) { - this.windowHandle = windowHandle; + setWindowHandle(windowHandle); } private long windowHandleClose; diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 0eb0f1571..13d549e24 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -35,404 +36,323 @@ package com.jogamp.newt.opengl; import com.jogamp.newt.*; import com.jogamp.newt.event.*; -import com.jogamp.newt.util.*; -import com.jogamp.nativewindow.impl.RecursiveToolkitLock; +import com.jogamp.newt.util.Insets; +import com.jogamp.newt.impl.WindowImpl; import javax.media.nativewindow.*; import javax.media.opengl.*; import com.jogamp.opengl.impl.GLDrawableHelper; -import java.util.*; /** - * An implementation of {@link Window} which is customized for OpenGL - * use, and which implements the {@link javax.media.opengl.GLAutoDrawable} interface. + * An implementation of {@link javax.media.opengl.GLAutoDrawable} interface, + * using an aggregation of a {@link com.jogamp.newt.Window} implementation. * <P> * This implementation does not make the OpenGL context current<br> - * before calling the various input EventListener callbacks (MouseListener, KeyListener, - * etc.).<br> - * This design decision is made to favor a more performant and simplified - * implementation, as well as the event dispatcher shall be allowed - * not having a notion about OpenGL. + * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br> + * This design decision is made in favor of a more performant and simplified + * implementation. Also the event dispatcher shall be implemented OpenGL agnostic.<br> + * To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},<br> + * you can inject {@link javax.media.opengl.GLRunnable} objects + * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.<br> * <p> */ -public class GLWindow extends Window implements GLAutoDrawable { - private Window window; +public class GLWindow implements GLAutoDrawable, Window { + private WindowImpl window; /** * Constructor. Do not call this directly -- use {@link #create()} instead. */ protected GLWindow(Window window) { - this.startTime = System.currentTimeMillis(); - this.window = window; - this.window.setHandleDestroyNotify(false); + resetPerfCounter(); + this.window = (WindowImpl) window; + ((WindowImpl)this.window).setHandleDestroyNotify(false); window.addWindowListener(new WindowAdapter() { public void windowRepaint(WindowUpdateEvent e) { - if( !windowIsLocked() && null == getAnimator() ) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { display(); } } public void windowResized(WindowEvent e) { sendReshape = true; - if( !windowIsLocked() && null == getAnimator() ) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { display(); } } public void windowDestroyNotify(WindowEvent e) { - if( !windowIsLocked() && null == getAnimator() ) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { destroy(); } else { sendDestroy = true; } } }); + this.window.setLifecycleHook(new GLLifecycleHook()); } - /** Creates a new GLWindow attaching the given window - not owning the Window. */ - public static GLWindow create(Window window) { - return create(null, window, null, false); - } - - /** Creates a new GLWindow attaching a new native child Window of the given <code>parentNativeWindow</code> - with the given GLCapabilities - owning the Window */ - public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilities caps) { - return create(parentNativeWindow, null, caps, false); - } - - /** Creates a new GLWindow attaching a new decorated Window on the local display, screen 0, with a - dummy visual ID and given GLCapabilities - owning the window */ + /** + * Creates a new GLWindow attaching a new Window referencing a new Screen + * with the given GLCapabilities. + * <P> + * The resulting GLWindow owns the Window, Screen and Device, ie it will be destructed. + */ public static GLWindow create(GLCapabilities caps) { - return create(null, null, caps, false); + return new GLWindow(NewtFactory.createWindow(caps)); } - /** Creates a new GLWindow attaching a new Window on the local display, screen 0, with a - dummy visual ID and given GLCapabilities - owning the window */ - public static GLWindow create(GLCapabilities caps, boolean undecorated) { - return create(null, null, caps, undecorated); + /** + * Creates a new GLWindow attaching a new Window referencing the given Screen + * with the given GLCapabilities. + * <P> + * The resulting GLWindow owns the Window, ie it will be destructed. + */ + public static GLWindow create(Screen screen, GLCapabilities caps) { + return new GLWindow(NewtFactory.createWindow(screen, caps)); } - /** Either or: window (prio), or caps and undecorated (2nd choice) */ - private static GLWindow create(NativeWindow parentNativeWindow, Window window, - GLCapabilities caps, - boolean undecorated) { - if (window == null) { - if (caps == null) { - caps = new GLCapabilities(null); // default .. - } - window = NewtFactory.createWindow(parentNativeWindow, caps, undecorated); - } - + /** + * Creates a new GLWindow attaching the given window. + * <P> + * The resulting GLWindow does not own the given Window, ie it will not be destructed. + */ + public static GLWindow create(Window window) { return new GLWindow(window); } - - public boolean isNativeValid() { - return (null!=window)?window.isNativeValid():false; - } - - public boolean isValid() { - return (null!=window)?window.isValid():true; - } - - public final Window getInnerWindow() { - return window.getInnerWindow(); - } - public final Object getWrappedWindow() { - return window.getWrappedWindow(); - } - - protected void createNativeImpl() { - shouldNotCallThis(); - } - - protected void closeNativeImpl() { - shouldNotCallThis(); - } - - class DisposeAction implements Runnable { - public void run() { - // Lock: Covered by DestroyAction .. - helper.dispose(GLWindow.this); - } + /** + * Creates a new GLWindow attaching a new child Window + * of the given <code>parentNativeWindow</code> with the given GLCapabilities. + * <P> + * The Display/Screen will be compatible with the <code>parentNativeWindow</code>, + * or even identical in case it's a Newt Window. + * <P> + * The resulting GLWindow owns the Window, ie it will be destructed. + */ + public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilities caps) { + return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps)); } - private DisposeAction disposeAction = new DisposeAction(); - - class DestroyAction implements Runnable { - boolean unrecoverable; - public DestroyAction(boolean unrecoverable) { - this.unrecoverable = unrecoverable; - } - public void run() { - // Lock: Have to cover whole workflow (dispose all, context, drawable and window) - windowLock(); - try { - if( !isValid() ) { - return; // nop - } - if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - Exception e1 = new Exception("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", start: "+GLWindow.this); - e1.printStackTrace(); - } - - if( window.isNativeValid() && null != drawable && drawable.isRealized() ) { - if( null != context && context.isCreated() ) { - // Catch dispose GLExceptions by GLEventListener, just 'print' them - // so we can continue with the destruction. - try { - helper.invokeGL(drawable, context, disposeAction, null); - } catch (GLException gle) { - gle.printStackTrace(); - } - - context.destroy(); - context = null; - } - - drawable.setRealized(false); - drawable = null; - } - - if(null!=window) { - window.destroy(unrecoverable); - } - if(unrecoverable) { - helper=null; - } - if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - System.out.println("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", fin: "+GLWindow.this); - } - } finally { - windowUnlock(); - } - } - } + //---------------------------------------------------------------------- + // Window Access + // - public void destroy(boolean unrecoverable) { - if( isValid() ) { - runOnEDTIfAvail(true, new DestroyAction(unrecoverable)); + public final Capabilities getChosenCapabilities() { + if (drawable == null) { + return window.getChosenCapabilities(); } - } - - public boolean getPerfLogEnabled() { return perfLog; } - - public void enablePerfLog(boolean v) { - perfLog = v; - } - - protected void setVisibleImpl(boolean visible) { - shouldNotCallThis(); - } - - public void reparentWindow(NativeWindow newParent) { - window.reparentWindow(newParent); - } - class VisibleAction implements Runnable { - boolean visible; - public VisibleAction(boolean visible) { - this.visible = visible; - } - public void run() { - // Lock: Have to cover whole workflow (window, may do nativeCreation, drawable and context) - windowLock(); - try{ - window.setVisible(visible); - if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) { - NativeWindow nw; - if (getWrappedWindow() != null) { - nw = NativeWindowFactory.getNativeWindow(getWrappedWindow(), window.getGraphicsConfiguration()); - } else { - nw = window; - } - GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); - if(null==factory) { - factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); - } - if(null==drawable) { - drawable = factory.createGLDrawable(nw); - } - drawable.setRealized(true); - context = drawable.createContext(null); - sendReshape = true; // ensure a reshape event is send .. - } - } finally { - windowUnlock(); - } - } + return drawable.getChosenGLCapabilities(); } - public void setVisible(boolean visible) { - if(isValid()) { - runOnEDTIfAvail(true, new VisibleAction(visible)); - } + public final Capabilities getRequestedCapabilities() { + return window.getRequestedCapabilities(); } - public Capabilities getRequestedCapabilities() { - return window.getRequestedCapabilities(); + public final Window getWindow() { + return window; } - public NativeWindow getParentNativeWindow() { + public final NativeWindow getParentNativeWindow() { return window.getParentNativeWindow(); } - public Screen getScreen() { + public final Screen getScreen() { return window.getScreen(); } - public void setTitle(String title) { + public final void setTitle(String title) { window.setTitle(title); } - public String getTitle() { + public final String getTitle() { return window.getTitle(); } - public void setUndecorated(boolean value) { + public final void setUndecorated(boolean value) { window.setUndecorated(value); } - public boolean isUndecorated() { + public final boolean isUndecorated() { return window.isUndecorated(); } - public void requestFocus() { - window.requestFocus(); - } - public void setFocusAction(FocusRunnable focusAction) { + public final void setFocusAction(FocusRunnable focusAction) { window.setFocusAction(focusAction); } - - public Insets getInsets() { - return window.getInsets(); + + public final void requestFocus() { + window.requestFocus(); } - public void setSize(int width, int height) { - window.setSize(width, height); - } - protected void setSizeImpl(int width, int height) { - shouldNotCallThis(); + public final Insets getInsets() { + return window.getInsets(); } - public void setPosition(int x, int y) { + public final void setPosition(int x, int y) { window.setPosition(x, y); } - protected void setPositionImpl(int x, int y) { - shouldNotCallThis(); - } - public boolean setFullscreen(boolean fullscreen) { + public final boolean setFullscreen(boolean fullscreen) { return window.setFullscreen(fullscreen); } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { - shouldNotCallThis(); + + public final boolean isFullscreen() { + return window.isFullscreen(); } - public boolean isVisible() { + public final boolean isVisible() { return window.isVisible(); } - public int getX() { - return window.getX(); + public final String toString() { + return "NEWT-GLWindow[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable + + ", \n\tContext: " + context + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]"; } - public int getY() { - return window.getY(); + public final int reparentWindow(NativeWindow newParent) { + return window.reparentWindow(newParent); } - public int getWidth() { - return window.getWidth(); + public final int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { + return window.reparentWindow(newParent, forceDestroyCreate); } - public int getHeight() { - return window.getHeight(); + public final void removeChild(NativeWindow win) { + window.removeChild(win); } - public boolean isFullscreen() { - return window.isFullscreen(); + public final void addChild(NativeWindow win) { + window.addChild(win); } - public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { - window.enqueueEvent(wait, event); - } - public boolean consumeEvent(NEWTEvent e) { - return window.consumeEvent(e); - } + //---------------------------------------------------------------------- + // Window.LifecycleHook Implementation + // - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) { - window.addSurfaceUpdatedListener(index, l); - } - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - window.removeSurfaceUpdatedListener(l); - } - public void removeAllSurfaceUpdatedListener() { - window.removeAllSurfaceUpdatedListener(); - } - public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - return window.getSurfaceUpdatedListener(index); - } - public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - return window.getSurfaceUpdatedListeners(); - } - public void surfaceUpdated(Object updater, NativeWindow window0, long when) { - window.surfaceUpdated(updater, window, when); + public final void destroy(boolean unrecoverable) { + window.destroy(unrecoverable); } - public void addMouseListener(int index, MouseListener l) { - window.addMouseListener(index, l); - } - public void removeMouseListener(MouseListener l) { - window.removeMouseListener(l); - } - public MouseListener getMouseListener(int index) { - return window.getMouseListener(index); - } - public MouseListener[] getMouseListeners() { - return window.getMouseListeners(); + public final void setVisible(boolean visible) { + window.setVisible(visible); } - public void addKeyListener(int index, KeyListener l) { - window.addKeyListener(index, l); - } - public void removeKeyListener(KeyListener l) { - window.removeKeyListener(l); - } - public KeyListener getKeyListener(int index) { - return window.getKeyListener(index); - } - public KeyListener[] getKeyListeners() { - return window.getKeyListeners(); + public final void setSize(int width, int height) { + window.setSize(width, height); } - public void sendWindowEvent(int eventType) { - window.sendWindowEvent(eventType); - } - public void enqueueWindowEvent(boolean wait, int eventType) { - window.enqueueWindowEvent(wait, eventType); - } - public void addWindowListener(int index, WindowListener l) { - window.addWindowListener(index, l); - } - public void removeWindowListener(WindowListener l) { - window.removeWindowListener(l); - } - public WindowListener getWindowListener(int index) { - return window.getWindowListener(index); - } - public WindowListener[] getWindowListeners() { - return window.getWindowListeners(); - } - public void setPropagateRepaint(boolean v) { - window.setPropagateRepaint(v); - } - public void windowRepaint(int x, int y, int width, int height) { - window.windowRepaint(x, y, width, height); + public final boolean isValid() { + return window.isValid(); } - public String toString() { - return "NEWT-GLWindow[ \n\tHelper: "+helper+", \n\tDrawable: "+drawable + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]"; + public final boolean isNativeValid() { + return window.isNativeValid(); } + // Hide methods here .. + protected class GLLifecycleHook implements WindowImpl.LifecycleHook { + + class DisposeAction implements Runnable { + public void run() { + // Lock: Covered by DestroyAction .. + helper.dispose(GLWindow.this); + } + } + DisposeAction disposeAction = new DisposeAction(); + + /** Window.LifecycleHook */ + public synchronized void destroyAction(boolean unrecoverable) { + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + String msg = new String("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", start"); + System.err.println(msg); + //Exception e1 = new Exception(msg); + //e1.printStackTrace(); + } + + if( window.isNativeValid() && null != drawable && drawable.isRealized() ) { + if( null != context && context.isCreated() ) { + // Catch dispose GLExceptions by GLEventListener, just 'print' them + // so we can continue with the destruction. + try { + helper.invokeGL(drawable, context, disposeAction, null); + } catch (GLException gle) { + gle.printStackTrace(); + } + context.destroy(); + } + drawable.setRealized(false); + } + context = null; + drawable = null; + + if(unrecoverable) { + helper=null; + } + + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + System.err.println("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", fin"); + } + } + + /** Window.LifecycleHook */ + public synchronized void setVisibleAction(boolean visible, boolean nativeWindowCreated) { + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + String msg = new String("GLWindow.setVisibleAction("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", start"); + System.err.println(msg); + // Exception e1 = new Exception(msg); + // e1.printStackTrace(); + } + + /* if (nativeWindowCreated && null != context) { + throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)"); + } */ + if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) { + NativeWindow nw; + if (window.getWrappedWindow() != null) { + nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); + } else { + nw = window; + } + GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + if(null==factory) { + factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); + } + if(null==drawable) { + drawable = factory.createGLDrawable(nw); + } + drawable.setRealized(true); + context = drawable.createContext(null); + resetPerfCounter(); + } else if(!visible) { + resetPerfCounter(); + } + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + String msg = new String("GLWindow.setVisibleAction("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", fin"); + System.err.println(msg); + //Exception e1 = new Exception(msg); + //e1.printStackTrace(); + } + } + + boolean animatorPaused = false; + + public synchronized void reparentActionPre() { + GLAnimatorControl ctrl = GLWindow.this.getAnimator(); + if ( null!=ctrl && ctrl.isAnimating() && ctrl.getThread() != Thread.currentThread() ) { + animatorPaused = true; + ctrl.pause(); + } + } + + public synchronized void reparentActionPost(int reparentActionType) { + resetPerfCounter(); + GLAnimatorControl ctrl = GLWindow.this.getAnimator(); + if ( null!=ctrl && animatorPaused ) { + animatorPaused = false; + ctrl.resume(); + } + } + } //---------------------------------------------------------------------- // OpenGL-related methods and state // @@ -445,6 +365,16 @@ public class GLWindow extends Window implements GLAutoDrawable { private boolean sendReshape=false; private boolean sendDestroy=false; private boolean perfLog = false; + private long startTime, curTime, lastCheck; + private int totalFrames, lastFrames; + + /** Reset all performance counter (startTime, currentTime, frame number) */ + public void resetPerfCounter() { + startTime = System.currentTimeMillis(); // overwrite startTime to real init one + curTime = startTime; + lastCheck = startTime; + totalFrames = 0; lastFrames = 0; + } public GLDrawableFactory getFactory() { return factory; @@ -485,15 +415,20 @@ public class GLWindow extends Window implements GLAutoDrawable { helper.removeGLEventListener(listener); } - public void setAnimator(Thread animator) { - helper.setAnimator(animator); - window.setPropagateRepaint(null==animator); + public void setAnimator(GLAnimatorControl animatorControl) { + helper.setAnimator(animatorControl); } - public Thread getAnimator() { + public GLAnimatorControl getAnimator() { return helper.getAnimator(); } + public boolean getPerfLogEnabled() { return perfLog; } + + public void enablePerfLog(boolean v) { + perfLog = v; + } + public void invoke(boolean wait, GLRunnable glRunnable) { helper.invoke(this, wait, glRunnable); } @@ -516,15 +451,15 @@ public class GLWindow extends Window implements GLAutoDrawable { setVisible(true); } - if( window.isVisible() && window.isNativeValid() && null != context ) { + if( isVisible() && isNativeValid() && null != context ) { if(forceReshape) { sendReshape = true; } - windowLock(); + lockSurface(); try{ helper.invokeGL(drawable, context, displayAction, initAction); } finally { - windowUnlock(); + unlockSurface(); } } } @@ -555,12 +490,7 @@ public class GLWindow extends Window implements GLAutoDrawable { public void run() { // Lock: Locked Surface/Window by MakeCurrent/Release helper.init(GLWindow.this); - startTime = System.currentTimeMillis(); // overwrite startTime to real init one - curTime = startTime; - if(perfLog) { - lastCheck = startTime; - totalFrames = 0; lastFrames = 0; - } + resetPerfCounter(); } } private InitAction initAction = new InitAction(); @@ -584,7 +514,7 @@ public class GLWindow extends Window implements GLAutoDrawable { dt0 = curTime-lastCheck; if ( dt0 > 5000 ) { dt1 = curTime-startTime; - System.out.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+ + System.err.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+ "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f"); lastCheck=curTime; lastFrames=0; @@ -594,15 +524,69 @@ public class GLWindow extends Window implements GLAutoDrawable { } private DisplayAction displayAction = new DisplayAction(); - public long getStartTime() { return startTime; } - public long getCurrentTime() { curTime = System.currentTimeMillis(); return curTime; } - public long getDuration() { return getCurrentTime()-startTime; } - public int getTotalFrames() { return totalFrames; } + /** + * @return Time of the first display call in milliseconds. + * This value is reset if becoming visible again or reparenting. + * In case an animator is used, + * the corresponding {@link javax.media.opengl.GLAnimatorControl} value is returned. + * + * @see javax.media.opengl.GLAnimatorControl#getStartTime() + */ + public final long getStartTime() { + GLAnimatorControl animator = getAnimator(); + if ( null == animator || null == animator.getThread() ) { + // no animator, or not started -> use local time + return startTime; + } else { + return animator.getStartTime(); + } + } - private long startTime = 0; - private long curTime = 0; - private long lastCheck = 0; - private int totalFrames = 0, lastFrames = 0; + /** + * @return Time of the last display call in milliseconds. + * This value is reset if becoming visible again or reparenting. + * In case an animator is used, + * the corresponding {@link javax.media.opengl.GLAnimatorControl} value is returned. + * + * @see javax.media.opengl.GLAnimatorControl#getCurrentTime() + */ + public final long getCurrentTime() { + GLAnimatorControl animator = getAnimator(); + if ( null == animator || null == animator.getThread() ) { + // no animator, or not started -> use local time + return curTime; + } else { + return animator.getCurrentTime(); + } + } + + /** + * @return Duration <code>getCurrentTime() - getStartTime()</code>. + * + * @see #getStartTime() + * @see #getCurrentTime() + */ + public final long getDuration() { + return getCurrentTime()-getStartTime(); + } + + /** + * @return Number of frames displayed since the first display call, ie <code>getStartTime()</code>. + * This value is reset if becoming visible again or reparenting. + * In case an animator is used, + * the corresponding {@link javax.media.opengl.GLAnimatorControl} value is returned. + * + * @see javax.media.opengl.GLAnimatorControl#getTotalFrames() + */ + public final int getTotalFrames() { + GLAnimatorControl animator = getAnimator(); + if ( null == animator || null == animator.getThread() ) { + // no animator, or not started -> use local value + return totalFrames; + } else { + return animator.getTotalFrames(); + } + } class SwapBuffersAction implements Runnable { public void run() { @@ -612,77 +596,53 @@ public class GLWindow extends Window implements GLAutoDrawable { private SwapBuffersAction swapBuffersAction = new SwapBuffersAction(); //---------------------------------------------------------------------- - // NativeWindow/Window methods + // GLDrawable methods // - public int lockSurface() throws NativeWindowException { - if(null!=drawable) return drawable.getNativeWindow().lockSurface(); - return window.lockSurface(); - } - - public void unlockSurface() { - if(null!=drawable) drawable.getNativeWindow().unlockSurface(); - else window.unlockSurface(); - } - - public boolean isSurfaceLocked() { - if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked(); - return window.isSurfaceLocked(); - } - - public Exception getLockedStack() { - if(null!=drawable) return drawable.getNativeWindow().getLockedStack(); - return window.getLockedStack(); + public final NativeWindow getNativeWindow() { + return null!=drawable ? drawable.getNativeWindow() : null; } - public boolean surfaceSwap() { - if(null!=drawable) return drawable.getNativeWindow().surfaceSwap(); - return super.surfaceSwap(); + public final long getHandle() { + return null!=drawable ? drawable.getHandle() : 0; } - public long getWindowHandle() { - if(null!=drawable) return drawable.getNativeWindow().getWindowHandle(); - return window.getWindowHandle(); + public final void destroy() { + window.destroy(); } - public long getSurfaceHandle() { - if(null!=drawable) return drawable.getNativeWindow().getSurfaceHandle(); - return window.getSurfaceHandle(); + public final int getX() { + return window.getX(); } - public AbstractGraphicsConfiguration getGraphicsConfiguration() { - if(null!=drawable) return drawable.getNativeWindow().getGraphicsConfiguration(); - return window.getGraphicsConfiguration(); + public final int getY() { + return window.getY(); } - //---------------------------------------------------------------------- - // GLDrawable methods - // - - public NativeWindow getNativeWindow() { - return null!=drawable ? drawable.getNativeWindow() : null; + public final int getWidth() { + return window.getWidth(); } - public long getHandle() { - return null!=drawable ? drawable.getHandle() : 0; + public final int getHeight() { + return window.getHeight(); } //---------------------------------------------------------------------- // GLDrawable methods that are not really needed // - public GLContext createContext(GLContext shareWith) { + public final GLContext createContext(GLContext shareWith) { return drawable.createContext(shareWith); } - public void setRealized(boolean realized) { + public final void setRealized(boolean realized) { } - public boolean isRealized() { + public final boolean isRealized() { return ( null != drawable ) ? drawable.isRealized() : false; } - public GLCapabilities getChosenGLCapabilities() { + public final GLCapabilities getChosenGLCapabilities() { if (drawable == null) { throw new GLException("No drawable yet"); } @@ -690,11 +650,177 @@ public class GLWindow extends Window implements GLAutoDrawable { return drawable.getChosenGLCapabilities(); } - public GLProfile getGLProfile() { + public final GLProfile getGLProfile() { if (drawable == null) { throw new GLException("No drawable yet"); } return drawable.getGLProfile(); } + + //---------------------------------------------------------------------- + // Window completion + // + public final void windowRepaint(int x, int y, int width, int height) { + window.windowRepaint(x, y, width, height); + } + + public final void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { + window.enqueueEvent(wait, event); + } + + public final void runOnEDTIfAvail(boolean wait, final Runnable task) { + window.runOnEDTIfAvail(wait, task); + } + + public final SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { + return window.getSurfaceUpdatedListener(index); + } + + public final SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { + return window.getSurfaceUpdatedListeners(); + } + + public final void removeAllSurfaceUpdatedListener() { + window.removeAllSurfaceUpdatedListener(); + } + + public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + window.removeSurfaceUpdatedListener(l); + } + + public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + window.addSurfaceUpdatedListener(l); + } + + public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + window.addSurfaceUpdatedListener(index, l); + } + + public void sendWindowEvent(int eventType) { + window.sendWindowEvent(eventType); + } + + public final WindowListener getWindowListener(int index) { + return window.getWindowListener(index); + } + + public final WindowListener[] getWindowListeners() { + return window.getWindowListeners(); + } + + public final void removeWindowListener(WindowListener l) { + window.removeWindowListener(l); + } + + public final void addWindowListener(WindowListener l) { + window.addWindowListener(l); + } + + public final void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException { + window.addWindowListener(index, l); + } + + public final void addKeyListener(KeyListener l) { + window.addKeyListener(l); + } + + public final void addKeyListener(int index, KeyListener l) { + window.addKeyListener(index, l); + } + + public final void removeKeyListener(KeyListener l) { + window.removeKeyListener(l); + } + + public final KeyListener getKeyListener(int index) { + return window.getKeyListener(index); + } + + public final KeyListener[] getKeyListeners() { + return window.getKeyListeners(); + } + + public final void addMouseListener(MouseListener l) { + window.addMouseListener(l); + } + + public final void addMouseListener(int index, MouseListener l) { + window.addMouseListener(index, l); + } + + public final void removeMouseListener(MouseListener l) { + window.removeMouseListener(l); + } + + public final MouseListener getMouseListener(int index) { + return window.getMouseListener(index); + } + + public final MouseListener[] getMouseListeners() { + return window.getMouseListeners(); + } + + //---------------------------------------------------------------------- + // NativeWindow completion + // + + public final int lockSurface() { + return window.lockSurface(); + } + + public final void unlockSurface() throws NativeWindowException { + window.unlockSurface(); + } + + public final boolean isSurfaceLockedByOtherThread() { + return window.isSurfaceLockedByOtherThread(); + } + + public final boolean isSurfaceLocked() { + return window.isSurfaceLocked(); + } + + public final Thread getSurfaceLockOwner() { + return window.getSurfaceLockOwner(); + + } + + public final Exception getSurfaceLockStack() { + return window.getSurfaceLockStack(); + } + + public final boolean surfaceSwap() { + return window.surfaceSwap(); + } + + public final void invalidate() { + window.invalidate(); + } + + public final long getWindowHandle() { + return window.getWindowHandle(); + + } + + public final long getSurfaceHandle() { + return window.getSurfaceHandle(); + + } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return window.getGraphicsConfiguration(); + } + + public final long getDisplayHandle() { + return window.getDisplayHandle(); + } + + public final int getScreenIndex() { + return window.getScreenIndex(); + } + + public final void surfaceUpdated(Object updater, NativeWindow window, long when) { + window.surfaceUpdated(updater, window, when); + } } |