diff options
author | Sven Gothel <[email protected]> | 2010-09-23 16:21:39 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-09-23 16:21:39 +0200 |
commit | 0feca163be47db2ea94f7546e696136d6f9496e9 (patch) | |
tree | acb22106e716b7a4670a280c53466cf30aad233c /src/newt/classes/com | |
parent | 46971a3b9d58bcd1e2305d0f428b31ce30273293 (diff) |
NEWT: Fix Display/Window/Screen OO Identity, Reparenting and requestFocus
NativeWindow: Interface NativeWindow changes:
- Remove 'throws' qualifier in lockSurface(), since it is not
- Adding convenient 'one call' isSurfaceLockedByOtherThread()
- Adding getSurfaceLockOwner()
NEWT Window/GLWindow:
- Unclutter Window/GLWindow relationship - save Window's indentity
GLWindow's role is a GLAutoDrawable implementation aggregating
(maybe even compositioning) a Window.
The previous implementation just derived from the Window implementation,
overwriting methods and fields - impossible to ensure sanity / completness.
It was also not ensured that the added functionality of GLWindow
(setVisible, destroy, ..) has been issued in case of handling the
aggregated Window alone (window callbacks, ..).
To solve this issue in a 1st attempt without changing the GLWindow API,
Window is just an interface, being implemented by their specializations,
hence sanity is intrinsic.
GLWindow's added functionality is ensured by a Window.LifecycleHook
interfaced implementation, registered at the aggregated Window.
- Screen and Window are interfaces now (new files)
- Display is an abstract class.
- Their (abstract) implementations resides in impl/<BaseName>Impl
- GLWindow implements Window as well
- Remove Screen reference handled by setScreen(Screen) method.
- Lock native parentWindow if used (createNative/reparenting)
- Move lockSurface/unlockSurface from unchecked override pattern
to an callback style using abstract methods lockSurfaceImpl/...
- Sorting all methods to semantic sections, abstract, superinterface, ..
- Reparenting: Handling different reparenting situations:
- Unchanged - No change
- Native Reparenting - Compatible Display/Screen, try native reparenting
- Native (Re)Creation - Use destroy/create pattern
- Native Creation Pending - Create later
- setUndecorated() calls reconfigure Window now, ie tries to change the window actually
- Don't issue 'requestFocus()' directly from the native implementation anymore,
call it from the Java code.
- Window/GLWindow/NewtFactory: Constructor simplification
Avoid explosion of constructor overloading, ie removing the 'undecorated' variant,
since this is redundant due to the 'setUndecorated(boolean)' method.
- Fixed/added API documentation
Diffstat (limited to 'src/newt/classes/com')
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); + } } |